Access to the additional information about users - django

I have read this and I have one question. How to take access to the 'other fields'?
models:
class UsersProfile(models.Model):
def __unicode__(self):
return self.user.last_name
user = models.OneToOneField(User)
car_num = models.IntegerField('car ID')
captain = models.BooleanField()
views:
#login_required
def profile(request):
return render(request, 'profile.html')
So, after authentication, in profile works only user.last_login + etc, but not user.car_num or user.captain. I read about get_profile(), but where I need it to write?
profile = request.user.get_profile()
If it in views, how to return?

You can define a related_name for your OneToOneField, like this:
user = models.OneToOneField(User, related_name='profile')
and then access the corresponding fields using
request.user.profile.car_num

Related

Users to see only their objects in Django

So I have an application where users can create their own Companies. But what I want in the view is for them to see only their entries on the view. I have seen similar questions on this platform but they don't work as expected. Below is my code.
Models.Py
from django.contrib.auth.models import User
class Company (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
company_name = models.CharField(max_length=100, null=True)
mailing_address = models.CharField(max_length=100, null=True)
physical_address = models.CharField(max_length=100, null=True)
class Meta:
verbose_name_plural = "Companies"
def __str__(self):
return self.company_name
views.py
#login_required(login_url='login')
def company (request):
all_companies = Company.objects.filter(user=request.user)
count= Company.objects.all().count()
context = {'all_companies': all_companies, 'count': count}
return render(request, 'company/company.html', context)
forms.py
class CompanyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CompanyForm, self).__init__(*args, **kwargs)
self.fields['company_name'].widget.attrs = {'class': 'input',}
self.fields['date_created'].widget.attrs = {'class': 'input',}
self.fields['mailing_address'].widget.attrs = {'class': 'input',}
self.fields['physical_address'].widget.attrs = {'class': 'input',}
class Meta:
model = Company
fields = ('company_name', 'date_created', 'mailing_address', 'physical_address',)
The so largely this works to ensure that every user only sees the company they have created. However, I can successfully create the companies from the admin side but a glaring issue appears. I have to manually select users from the form field = users in the admin form as shown in the picture below, to be able to create and save companies. It is the same behaviour on the front end with the form. This doesn't look right.
How can I ensure a company automatically points to the owner (user) who created it, without having to manually force the form to choose the user.
admin page
If you want the user to be added automatically in Django admin, you can override the save_model of its corresponding ModelAdmin:
https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
If you want it to be populated when users are creating companies using forms, you can set the user attribute like this:
# assuming request.user is available
company_form = form.save(commit=False)
company_form.user = request.user
company_form.save()
Since, user is the foreign key. You can take advantage of
'formfield_for_foreignkey' method in the ModelAdmin class.
This method gets executed for the foreign fields declared in the model. Here, we can check whether it has been executed for the user or not if yes, then we can prepopulate its value. You can customize the admin form by creating ModelAdmin class in admin.py for the Company model
#admin.register(Company)
class CompanyAdmin(admin.ModelAdmin):
form = CompanyForm
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'user':
kwargs['initial'] = request.user.id
return db_field.formfield(**kwargs)
return super(CompanyAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
In the ModelAdmin class you can specify the form class for further customizations.
Note, this will only prepopulate the value, the value of the user can be changed in the form. To avoid this, you can make user field uneditable and readonly field.
So I finally found the solution, at least for the user field in the Company form.
This gives a clear way of doing this: https://docs.djangoproject.com/en/4.0/topics/class-based-views/generic-editing/#models-and-request-user
In views.py: I added form.instance for the field user to ensure it picks the current user and feeds it in the form.
def company_form (request):
form = CompanyForm()
if request.method == 'POST':
# Request files helps upload other files such as images
form = CompanyForm(request.POST, request.FILES)
#This automatically inserts the user without exposing the form field
form.instance.user = request.user
if form.is_valid():
form.save()
return redirect('company')
Then I modified the model field for the user to ensure it is not editable.
models.py
class Company (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, editable=False)
This ensured no one can edit the user including the admin. That ideally solves 90 percent of my issues.
Appreciate everyone's help on this.

Django Formset: how to get the current user? (using django-extra-views)

I'm used to collecting the current logged in user in a CreateView and passing it to the form like so:
class MakeFantasyTeam(CreateView):
form_class = MakeFantasyTeamForm
[...]
def form_valid(self, form):
form.instance.team_manager = self.request.user
form.save()
return super(MakeFantasyTeam, self).form_valid(form)
However, this doesn't seem to work when using an InlineFormSetView as provided by django-extra-views. I get an error NOT NULL constraint failed: tournament_invite.invited_by_id and I'm not sure how to get the user.id passed on to the form.
My View:
class InvitePlayersView(InlineFormSetView):
template_name = 'invite_players.html'
model = Tournament
inline_model = Invite
form_class = InvitePlayerForm
pk_url_kwarg = 'tourney_id'
factory_kwargs = {'can_delete': False, 'extra': 1}
def formset_valid(self, formset):
tourney_id = self.kwargs['tourney_id']
formset.instance.invited_for = Tournament.objects.filter(id=tourney_id).get()
formset.instance.invited_by = self.request.user
formset.save()
return super(InvitePlayersView, self).formset_valid(formset)
def get_success_url(self):
return reverse('make_team', kwargs={'tourney_id': self.object.invited_for.id})
My Model:
class Invite(models.Model):
name = models.CharField(max_length=200, blank=True, null=True)
email = models.CharField(max_length=320, null=False, blank=False, validators=[EmailValidator],)
invited_by = models.ForeignKey(get_user_model(), on_delete=models.DO_NOTHING)
invited_for = models.ForeignKey(Tournament, on_delete=models.DO_NOTHING)
created_dt = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.email
def get_absolute_url(self):
return reverse('home')
My Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = Invite
fields = ('name', 'email',)
Any tips or hints much appreciated!
Thank you,
Jon
Edit: Just to clarify what I'm trying to do here; I want a user to submit a formset. The data of that formset should be stored in the model, and the userid of the submitting user should also be stored in the model. I don't seem to be able to pass on the userid though.
I am not sure what you exactly want to do here, As per my understanding you want to use the currently logged in user's information. To do so you can append the user's info in the session dictionary. After that you can use the information in templates or in other views too.
In authentication view
def login(request):
#your necessary data
request.session['user_id']=The_user_id
request.session['user_name']=The_userName
To access data in the template
{% request.session.user_id %}
{% request.session.user_name %}
To access data in other views
def myview(request):
user_id= request.session['user_id']
user_name= request.session['user_name']

Django: set user creating a post (creator of a row) automatically as creator/author [duplicate]

I'd like to do something like this:
class Task(models.Model):
...
created_by = models.ForeignKey(User, **default=[LoggedInUser]** blank=True, null=True, related_name='created_by')
Is this possible? I couldn't find what's the proper way to get the logged in user, apart from doing request.user, in a view, which doesn't seem to work here.
PS_ I realise I could initialize the Model data by other means, but I think this is the cleanest way.
If you want to achieve this within the admin interface, you can use the save_model method. See below an example:
class List(models.Model):
title = models.CharField(max_length=64)
author = models.ForeignKey(User)
class ListAdmin(admin.ModelAdmin):
fields = ('title',)
def save_model(self, request, obj, form, change):
obj.author = request.user
obj.save()
No, you can't do it this way. Django (and Python) has pretty much zero global values, and that's a Good Thing(tm). Normally you get the current user in the view(request) with request.user. You can then pass that as a param to various methods/functions, but trying to set a global user will only lead to tears in a multi-threaded environment.
There should be a bumper sticker that says, Globals are Evil. This will give you a good idea about my Number One problem with PHP.
SOLVED:
I will use an example, but the important part is the funciton on the views.py.
User is automatically available by django.
Note the 'autor' model field has a ForeignKey to the 'User'.
In the 'def form_valid' below I assign the currently logged in user as the default value.
If this is your model:
class ProspectoAccion(models.Model):
"""
Model representing a comment against a blog post.
"""
descripcion = models.TextField(max_length=1000)
autor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
accion_date = models.DateTimeField(auto_now_add=True)
prospecto= models.ForeignKey(Prospecto, on_delete=models.CASCADE)
tipo_accion = models.ForeignKey('Accion', on_delete=models.SET_NULL, null=True)
And you have a class based view, do the following:
class ProspectoAccionCreate(LoginRequiredMixin, CreateView):
"""
Form for adding una acción. Requires login (despues poner)
"""
model = ProspectoAccion
fields = ['tipo_accion','descripcion',]
def form_valid(self, form):
#Add logged-in user as autor of comment THIS IS THE KEY TO THE SOLUTION
form.instance.autor = self.request.user
# Call super-class form validation behaviour
return super(ProspectoAccionCreate, self).form_valid(form)
HERE IS AN EXAMPLE FROM THE DOCUMENTATION:
https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user
If use ModelForm, the following will fill a default value for a special field. such as, owner filed is a charfield for user's name
def fillview(request):
instance = YourModel(owner=request.user.username)
form = YourModelForm(instance=instance)
if request.method == 'POST':
form = YourModelForm(request.POST, request.FILES)
if form.is_valid():
pass
return render(request, 'success.html')
return render(request, 'fill.html', {'form': form})
When logged in, you could see owner filed is current user's name.
By default, Django already creates a "created_by" attribute. You don't need to create your own.
If you nonetheless need to save this information separately to, let's say, have the possibility to change the user later on without affecting the original creator value, then you could override the save function to retrieve the value that Django assigns by default to "created_user":
class Application(models.Model):
property = models.ForeignKey(Property, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='applications', editable=False, null=True)
...
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not self.user:
self.user = self.created_by
super(Application, self).save(*args, **kwargs)

Multiple User Profile with Django Userena

I'm using userena 1.2 and Django 1.4. I'm trying to create multiple user profiles but I had no luck following many post found here on SO.
I've create 2 custom Models and a form like so:
class BaseProfile(UserenaBaseProfile):
""" Default profile """
user = models.OneToOneField(User, unique=True, verbose_name = _('user'), related_name='base_profile')
#property # accessing a method as a property
def is_seller(self):
"""Find out if this is a Seller user"""
try:
self.seller
return True
except Seller.DoesNotExist:
return False
def get_profile_type(self):
"""return the profile type model"""
if self.is_seller:
return self.seller
else:
return self.customer
class Seller(BaseProfile):
company = models.CharField(_('Company'),max_length=100, null=True, blank=True,)
class Customer(BaseProfile):
favourite_snack = models.CharField( _('favourite snack'), max_length=5 )
And overridden the Signup form:
class SignupFormExtra(SignupForm):
# stuff in here
def save(self):
# stuff in here
Now the problem is inside the save method.
Based on this answer I've tried to implement a custom manager but I had no luck (I'm a django newbie). The important point that I understood is that the Save method shoud return a Django User, not a userena profile.
def save(self):
user = super(SpamSignupForm,self).save()
new_customer = Customer.objects.create_user()
return new_user
Then I've tried something like this:
def save(self):
new_user = super(SignupFormExtra, self).save()
new_user.save()
customer = Customer(profile = new_user.get_profile(), user=new_user)
customer.save()
return new_user
The get_profile() method will always (I guess) returns the base profile defined in settings.AUTH_PROFILE_MODULE.
Also it seems wrong to me that the author used a profile field in the subprofile as a OneToOne relation to the Baseprofile WHILE implementing a multi-table inheritance, why? It doesn't seem right to me.
class Customer(Baseprofile):
profile = models.OneToOneField(Baseprofile,
unique=True,
verbose_name=_('profile'),
related_name='student')
Yes, basically I've spent a full day trying to figure this out and I'm still lost.
it is better to use django-registration. install and add it to INSTALLED_APPS =(.....'registration',
now create two user in
registration/models.py
.................
class Seller(models.Model):
user=models.OneToOneField(User)
companyname= models.CharField(max_length=100,blank=True)
def __unicode__(self):
return self.user.username
class Customer(models.Model):
user=models.OneToOneField(User)
birth_date = models.DateField(null=True, blank=True)
favourite_snack = models.CharField(max_length=5)
def __unicode__(self):
return self.user.username
in registration/views.py
........
from django.contrib.auth import authenticate, login
from registration.models import Seller,Customer
from django.http import HttpResponse
def auth_login(request,utype):
temp_login='registration/%slogin.html' %utype
try:
username = request.POST['username']
password = request.POST['password']
except KeyError:
return render(request,temp_login)
user = authenticate(username=username, password=password)
if utype=='seller':
try:Seller.objects.get(user=user)
except: return render(request,temp_login,{'errors':True})
if utype=='customer':
try:Customer.objects.get(user=user)
except: return render(request,temp_login,{'errors':True})
if user.is_active:
login(request,user)
return HttpResponseRedirect('/'+request.GET['next'])#,render(request,'%s/home.html' %utype)
return render(request,temp_login,{'errors':True})
edit registration/auth_urls.py
urlpatterns = patterns('',
url(r'^login/(employer|jobseeker)/$',
auth_login,name='auth_login'),
registration/backends/default/views.py
inside class RegistrationView(BaseRegistrationView):
inside def register(self, request, **cleaned_data): add
if self.args[0]=='e': usertype=Seller()
else: usertype=Customer()
usertype.user=new_user
usertype.save()
registration/backends/default/urls.py
add these line
url(r'^register/([ej])/$',
RegistrationView.as_view(),
name='registration_register'),

How to assign currently logged in user as default value for a model field?

I'd like to do something like this:
class Task(models.Model):
...
created_by = models.ForeignKey(User, **default=[LoggedInUser]** blank=True, null=True, related_name='created_by')
Is this possible? I couldn't find what's the proper way to get the logged in user, apart from doing request.user, in a view, which doesn't seem to work here.
PS_ I realise I could initialize the Model data by other means, but I think this is the cleanest way.
If you want to achieve this within the admin interface, you can use the save_model method. See below an example:
class List(models.Model):
title = models.CharField(max_length=64)
author = models.ForeignKey(User)
class ListAdmin(admin.ModelAdmin):
fields = ('title',)
def save_model(self, request, obj, form, change):
obj.author = request.user
obj.save()
No, you can't do it this way. Django (and Python) has pretty much zero global values, and that's a Good Thing(tm). Normally you get the current user in the view(request) with request.user. You can then pass that as a param to various methods/functions, but trying to set a global user will only lead to tears in a multi-threaded environment.
There should be a bumper sticker that says, Globals are Evil. This will give you a good idea about my Number One problem with PHP.
SOLVED:
I will use an example, but the important part is the funciton on the views.py.
User is automatically available by django.
Note the 'autor' model field has a ForeignKey to the 'User'.
In the 'def form_valid' below I assign the currently logged in user as the default value.
If this is your model:
class ProspectoAccion(models.Model):
"""
Model representing a comment against a blog post.
"""
descripcion = models.TextField(max_length=1000)
autor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
accion_date = models.DateTimeField(auto_now_add=True)
prospecto= models.ForeignKey(Prospecto, on_delete=models.CASCADE)
tipo_accion = models.ForeignKey('Accion', on_delete=models.SET_NULL, null=True)
And you have a class based view, do the following:
class ProspectoAccionCreate(LoginRequiredMixin, CreateView):
"""
Form for adding una acción. Requires login (despues poner)
"""
model = ProspectoAccion
fields = ['tipo_accion','descripcion',]
def form_valid(self, form):
#Add logged-in user as autor of comment THIS IS THE KEY TO THE SOLUTION
form.instance.autor = self.request.user
# Call super-class form validation behaviour
return super(ProspectoAccionCreate, self).form_valid(form)
HERE IS AN EXAMPLE FROM THE DOCUMENTATION:
https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user
If use ModelForm, the following will fill a default value for a special field. such as, owner filed is a charfield for user's name
def fillview(request):
instance = YourModel(owner=request.user.username)
form = YourModelForm(instance=instance)
if request.method == 'POST':
form = YourModelForm(request.POST, request.FILES)
if form.is_valid():
pass
return render(request, 'success.html')
return render(request, 'fill.html', {'form': form})
When logged in, you could see owner filed is current user's name.
By default, Django already creates a "created_by" attribute. You don't need to create your own.
If you nonetheless need to save this information separately to, let's say, have the possibility to change the user later on without affecting the original creator value, then you could override the save function to retrieve the value that Django assigns by default to "created_user":
class Application(models.Model):
property = models.ForeignKey(Property, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='applications', editable=False, null=True)
...
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if not self.user:
self.user = self.created_by
super(Application, self).save(*args, **kwargs)