Querying Django model object - django

I can query the user's profile using the user_id in the UserProfile model below. But I would like to use the username in the django.contrib.auth.models.User.username in the urls instead.
The urls.py currently looks like:
path('profile/<int:user_id>', login_required(views.UserProfileDetail), name='userprofile'),
So as against the above urls, I would like to use something like:
path('profile/<str:username>', login_required(views.UserProfileDetail), name='userprofile'),
Any idea how to write the query correctly? All attempts so far returns an error
views.py:
def UserProfileDetail(request, user_id, *args, **kwargs):
profile = UserProfile.objects.get(user_id = user_id)
profile_display = {'profiledetail': profile }
return render(request, 'main/userprofile.html', context=profile_display)
this is what the model looks like:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='userprofile')
userPhone = models.IntegerField(blank=True, null=True)
location = models.CharField(max_length=100, blank=True, null=True)

You can accept both a user_id and a username with a default value, and then query with Q objects to look for a UserProfile where at least one of the two matches. The paths guarantee that one is passed:
from django.contrib.auth.decorators import login_required
from django.db.models import Q
#login_required
def UserProfileDetail(request, user_id=None, username=None):
profile = UserProfile.objects.get(
Q(user_id=user_id) | Q(user__username=username)
)
profile_display = {'profiledetail': profile }
return render(request, 'main/userprofile.html', context=profile_display)
You might want to use login_required as a decorator instead. This avoids wrapping the view each time in a login_required.
Note: Functions are normally written in snake_case, not PerlCase, therefore it is
advisable to rename your function to user_profile_detail, not UserProfileDetail.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Related

Django Display User as user Full Name in Admin Field

I got stuck when trying to display User foreign as use full name
models.py
class Customer(models.Model):
name = models.charfield(max_length=100)
sales = models.foreignkey(User, on_delete=models.CASADE)
admin.py
#admin.register(Customer)
list_display = ('name', 'sales')
nah by default sales as user foreign display as username. But i want display it to first name or full name
Edited
You can add a method in the ModelAdmin, as mentioned by #dirkgroten in the comments below:
from django.contrib import admin
#admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin)
list_display = ('name', 'sales_first_name')
def sales_first_name(self, obj):
return obj.sales.first_name + obj.sales_last_name
The upside is you can handle null values as you wish, if your foreign key is not required, e.g.
def sales_first_name(self, obj):
if obj.sales:
return obj.sales.first_name
else:
return None # or return 'nobody'
Old answer
(which, as mentioned in the comments, does not work (unless you use a plugin like django-related-admin))
Maybe use sales__first_name instead?
list_display = ('name', 'sales__first_name')
This way django will evaluate the first_name attribute of the user object instead of returning the default string representation (defined by the __str__ method in the user model, which returns just the username).

2 Users in one model

New to Django. I'm trying to develop a Feedback module, but designing a database structure makes me confused for various reasons:
Where do I need to store feedback_score (positive/neutral/negative feedback ratio), should it be put in custom User, or somewhere else?
How should I get the recipient of the feedback credentials, should it be passed by URL, how to link recipient to FeedbackModel in class-based-views?
How to feedback_score to be calculated each time for every User?
models.py
User = get_user_model()
# Create your models here.
class FeedbackModel(models.Model):
id = models.AutoField(primary_key=False, db_column='id')
sender = models.ForeignKey(
User,
on_delete=models.CASCADE,
primary_key=False, related_name='feedback_left_by')
# recipient = models.ForeignKey(
# User,
# on_delete=models.CASCADE,
# primary_key=True)
FEEDBACK_OPTION = (
(-1, 'Negative'),
(0, 'Neutral'),
(+1, 'Good'),
)
feedback = models.IntegerField(choices=FEEDBACK_OPTION)
opinion = models.CharField(max_length=255)
class Meta:
ordering = ['left_by', '-id']
urls.py
from django.urls import path
from . import views
app_name = 'feedback'
urlpatterns = [
path('leave_feedback/<str:left_to>/',
views.leave_feedback.as_view(), name='leavefeedback'),
]
views.py
from django.shortcuts import render, reverse
from django.views.generic import TemplateView, CreateView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from .models import FeedbackModel
decorators = [login_required]
#method_decorator(decorators, name='dispatch')
class leave_feedback(CreateView):
model = FeedbackModel
fields = ['feedback', 'opinion']
success_url = '/'
#template_name = "feedback/leave_feedback.html"
def form_valid(self, form):
form.instance.sender = self.request.user
# ?
return super().form_valid(form)
custom user
class User(AbstractUser):
(...)
#property
def feedback_score(self)
return ???
feedback_score should be a class method in FeedbackModel, not a field. In general, you do not want fields in your database that can directly be derived from other fields. For instance:
class Person(models.Model):
name = models.CharField()
birthdate = models.DateField()
zodiac_sign = models.CharField()
If i have the birth date, I can easily get the zodiac sign. So, zodiac_sign should be a method. The same applies to your case. Just create a method that returns summary information on the feedback.
Where do I need to store feedback_score (positive/neutral/negative feedback ratio), should it be put in custom User, or somewhere else?
I think you current Model design is okay with the requirement. Just fix the ordering in class Meta.
BTW, if you want the user to have only one feedback, then consider using OneToOneField. If you want ratio of Feedback, just do like this:
feedbacks = Feeback.objects.all()
positive_feedbacks = feedbacks.filter(feedback=1).count() # returns count of the feedback
negative_feedbacks = feedbacks.filter(feedback=-1).count() # returns count of the feedback
neutral_feedbacks = feedbacks.filter(feedback=0).count() # returns count of the feedback
print("Ratio Positive:Negative:Neutral = {}:{}:{}".format(positive_feedbacks/negative_feedbacks, 1, neutral_feedbacks/negative_feedbacks)
How should I get the recipient of the feedback credentials, should it be passed by URL, how to link recipient to FeedbackModel in class-based-views?
You need to make the user login to the system. For example you can follow this tutorial but there are other good examples out there. Once you login into the system, the user is available via request.user. And your current implement reflects this as well.
How to feedback_score to be calculated each time for every User?
You can get the latest feedback by:
user = User.objects.get(id=1) # or user = request.user
latest_feedback = user.feedback_left_by.last()

Django custom user login, with different types of users

I've got an extended user model that has three boolean variables, indicating what type the user is:
class MyUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
newField = models.CharField(max_length=30)
isTypeA = models.BooleanField(default=False)
isTypeB = models.BooleanField(default=False)
i'm also writing a test for a class based view, called typeCheck
from django.shortcuts import render
from django.contrib.auth.models import User
from .models import MyUser
from django.contrib.auth.decorators import user_passes_test
def typeCheck(User):
return User.isTypeA
#user_passes_view(typeCheck, login_url='/login')
def typeAView(request):
...
when I try accessing the view, I get an error saying: 'User' object has no attribute 'isA'. How do I correctly acces the fields of my extended user model? I also tried
return User.MyUser.isTypeA
but that just returns an error saying: 'User' object has no attribute 'MyUser'
Your typeCheck takes user and should be return user.myuser.isTypeA
You're confusing Python by having a method parameter that is the same as a class you're trying to import, you could remedy this by changing the method argument to be lowercase which also follows pep8 naming convention
def typeCheck(user):
return user.myuser.isTypeA

Why do I have to reference the user model this way

I was working on a Django project and I was trying to do something like this to make sure that my model worked no matter what user model is set.
from django.contrib.auth import get_user_model
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(get_user_model())
However when I did this it resulted in errors telling me the user model couldn't be accessed so I had to change it to this
from django.conf import settings
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(settings.AUTH_USER_MODEL)
This works fine but I thought I have done this in the past using the first method. The only difference that time being that I was using a custom user model. They both seem like they are doing the same thing to me so why do I have to use the second method? And does get_user_model() not work with the default user?
This is the source code of the get_user_model() in django:
def get_user_model():
"""
Returns the User model that is active in this project.
"""
from django.db.models import get_model
try:
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
user_model = get_model(app_label, model_name)
if user_model is None:
raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL)
return user_model
As you can see, it pulls the AUTH_USER_MODEL variable from your settings as you do but extracting the app_label and the user class itself. If it does not work you should see one of the two errors in the terminal when this call is done.
I think your answer lies in the Django source. It depends on your setup what happens. Older versions might do it a bit differently.

Django social_auth custom user model FacebookBackend explanation

I'm trying to use social_auth (omab) for the first time and I'm find that there is no working example how to store basic facebook user data. Authentication works and user is created without problem as it's explained in the social_auth docs but I need to store gender and locale also. Both of them belongs to the basic facebook user data so they are in the facebook response all the time.
I'm use Django 1.4, Python2.7 and latest social_auth. So I was try to use SOCIAL_AUTH_USER_MODEL = 'myapp.UserProfile' in settings.py file and model.py is:
#!/usr/bin/python
#-*- coding: UTF-8 -*-
from django.db import models
from django.contrib.auth.models import User
from django.db.models import signals
import datetime
from datetime import timedelta
from django.db.models.signals import post_save
from social_auth.signals import pre_update
from social_auth.backends.facebook import FacebookBackend
class CustomUserManager(models.Manager):
def create_user(self, username, email):
return self.model._default_manager.create(username=username)
class UserProfile(models.Model):
gender = models.CharField(max_length=150, blank=True)
locale = models.CharField(max_length=150, blank=True)
#social_auth requirements
username = models.CharField(max_length=150)
last_login = models.DateTimeField(blank=True)
is_active = models.BooleanField()
objects = CustomUserManager()
class Meta:
verbose_name_plural = 'Profiles'
def __unicode__(self):
return self.username
def get_absolute_url(self):
return '/profiles/%s/' % self.id
def facebook_extra_values(sender, user,response, details, **kwargs):
profile = user.get_profile()
current_user = user
profile, new = UserProfile.objects.get_or_create(user=current_user)
profile.gender = response.get('gender')
profile.locale = response.get('locale')
profile.save()
return True
pre_update.connect(facebook_extra_values, sender=FacebookBackend, weak = False, dispatch_uid = 'facebook_extra_values_user')
In the settings.py I'm define pipeline
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
#'social_auth.backends.pipeline.associate.associate_by_email',
'social_auth.backends.pipeline.user.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
'social_auth.backends.pipeline.misc.save_status_to_session',
)
but with above I get error AssertionError: ForeignKey(None) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
Also I was try to use AUTH_PROFILE_MODULE = 'myapp.UserProfile' instead as I was do before to extend user.model, which works well but don't understand how to populate needed data when UserProfile is created. Does anyone can place working code for this problem?
Thanks
There are a couple of ways to archive it, what fits better to your project is up to you of course, here's a list of available options:
Define this setting FACEBOOK_EXTRA_DATA = ('gender', 'locale'), the values will be available at the UserSocialAuth instance, to get them just do user.social_auth.get(provider='facebook').extra_data['gender'] or ['locale']. This is possible just because the information is available in the basic user data response.
Use a user profile to store this data (check django doc about it). Then just add a pipeline entry that stores the values in your profile instance.
Create a custom user model, SOCIAL_AUTH_USER_MODEL = 'myapp.CustomUser', and again add a custom pipeline entry that stores the values in your user instance.
Number 1 is not the best solution IMO, since a user can have several Facebook accounts connected and it could create a mess. Number 2 is good for Django 1.4 and lower, but it's deprecated starting from Django 1.5, something to take into account. Number 3 is a bit messy IMO.