如何解决社交 django 'NoneType' 对象没有属性 'city_set'
如果我使用 Facebook 帐户登录,当我尝试更新我的用户个人资料时出现错误('nonetype' 对象没有属性 'city_set')。我假设问题是由以下原因引起的:最初没有选择国家和城市。正常注册和更新用户个人资料没有问题,但是social_django违反了规则。我正在使用 abstractbaseuser 模型,并且它有一个国家-城市模型。我尝试了很多方法来解决这个问题,但这些都没有帮助。非常感谢您提前抽出时间...
settings.py
"""
Django settings for project_folder project.
Generated by 'django-admin startproject' using Django 3.0.6.
For more information on this file,see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values,see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR,...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# Security WARNING: keep the secret key used in production secret!
SECRET_KEY = '7aa*ng4P*o!9h4%hyfgu=9xy69aumg6hzbz3g)1mf^4!+gi+e0'
# Security WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application deFinition
INSTALLED_APPS = [
'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',# apps
'apps.daily_brief','apps.users','apps.crm',# side-apps
'crispy_forms','django_cleanup','phonenumber_field','social_django','verify_email',]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',#social_django
'social_django.middleware.socialAuthExceptionMiddleware',]
#social_django
AUTHENTICATION_BACKENDS = (
'social_core.backends.github.GithubOAuth2','social_core.backends.twitter.TwitterOAuth','social_core.backends.facebook.FacebookOAuth2','django.contrib.auth.backends.ModelBackend',)
#social_django
SOCIAL_AUTH_FACEBOOK_KEY = '******************' # App ID
SOCIAL_AUTH_FACEBOOK_SECRET = '***********************' # App Secret
SOCIAL_AUTH_FACEBOOK_ScopE = ['email']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_ParaMS = {
'fields': 'id,name,email,gender,birthday,link,location,hometown,first_name,last_name',}
#social_django
# SOCIAL_AUTH_PIPELINE = (
# 'social_core.pipeline.social_auth.social_details',# 'social_core.pipeline.social_auth.social_uid',# 'social_core.pipeline.social_auth.auth_allowed',# 'social_core.pipeline.social_auth.social_user',# 'social_core.pipeline.user.get_username',# 'social.pipeline.social_auth.associate_by_email',# 'social.pipeline.user.create_user',# 'social_core.pipeline.social_auth.associate_user',# 'social_core.pipeline.social_auth.load_extra_data',# 'social_core.pipeline.user.user_details',# 'social_core.pipeline.debug.debug',# 'apps.users.pipeline.save_account',# create a model in users and add here
# )
ROOT_URLconf = 'project_folder.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates','Dirs': [BASE_DIR + '/templates/',],'APP_Dirs': True,'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',},]
AUTH_USER_MODEL = 'users.Account'
Wsgi_APPLICATION = 'project_folder.wsgi.application'
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS,JavaScript,Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_Dirs = (os.path.join(BASE_DIR,'static'),)
STATIC_ROOT = os.path.join(BASE_DIR,'staticfiles')
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'
try:
from project_folder.local_settings import *
except ImportError:
print('local_settings error')
pass
CRISPY_TEMPLATE_PACK = 'bootstrap4'
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'daily_brief_home'
logoUT_URL = 'logout'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ['DB_USER']
EMAIL_HOST_PASSWORD = os.environ['DB_PASS']
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager
from PIL import Image
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField
from django.utils.text import slugify
from .utils import unique_slug_generator_account
from django.db.models.signals import pre_save
from django.urls import reverse
class Country(models.Model):
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country,on_delete=models.CASCADE)
name = models.CharField(max_length=40)
def __str__(self):
return self.name
class AccountManager(BaseUserManager):
def create_user(self,username,password=None): # username field and required fields in Account database must be here
if not email:
raise ValueError("Users must have an email adress")
if not username:
raise ValueError("Users must have an username")
user = self.model( #if email and username condition passes in the top,than we can create the account
email=self.normalize_email(email),# normalize convert the characters to lowercase
username=username,)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,password):
user = self.create_user( #if email and username condition passes in the top,# normalize convert the characters to lowercase
password=password,username=username,)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(max_length=60,unique=True)
username = models.CharField(max_length=30,unique=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)
company = models.CharField(default='',max_length=200,help_text='In order to share the application with other users; you need to provide a valid company information',blank=True,null=True)
phone = PhoneNumberField('Phone Number',default='',help_text='Kindly use the global formatting without spaces (+90 531 531 53 53 = +905315315353)',unique=True,null=True)
first_name = models.CharField(max_length=100,null=True)
last_name = models.CharField(max_length=100,null=True)
GENDER_LIST=(
('Male','Male'),('Female','Female')
)
gender = models.CharField(max_length=100,choices=GENDER_LIST,null=True)
birthday = models.DateField(help_text='Kindly provide a global date formatting as follows: (YYYY-MM-DD)',auto_Now=False,null=True)
country = models.ForeignKey(Country,on_delete=models.SET_NULL,null=True)
city = models.ForeignKey(City,null=True)
district = models.CharField(max_length=100,null=True)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
slug = models.SlugField(max_length=200,null=True)
USERNAME_FIELD = 'email'
required_FIELDS = ['username'] #username and password are required by default
objects = AccountManager() # tells this Account database that; the manager database which is in the top AccountManager
def __str__(self):
return f'{self.email}'
def has_perm(self,perm,obj=None): # has permissions; if user is an admin; he can change stuff in the database
return self.is_admin
def has_module_perms(self,app_label): # has module permissions;
return True
# return self.is_admin
def get_absolute_url(self):
return reverse('account_detailview',kwargs={'pk': self.pk})
def pre_save_receiver(sender,instance,*args,**kwargs):
if instance.slug:
instance.slug = slugify(instance.username)
else:
instance.slug = slugify(instance.username)
pre_save.connect(pre_save_receiver,sender = Account)
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Account,City
from django.shortcuts import render,redirect
class AccountForm(UserCreationForm,forms.ModelForm):
class Meta:
model = Account
# fields = '__all__'
fields = ('email','username','password1','password2','company','phone','first_name','last_name','gender','birthday','country','city','district','image')
def __init__(self,**kwargs):
super().__init__(*args,**kwargs)
self.fields['city'].queryset = City.objects.none()
if 'country' in self.data:
try:
country_id = int(self.data.get('country'))
self.fields['city'].queryset = City.objects.filter(country_id=country_id).order_by('name')
except (ValueError,TypeError):
pass # invalid input from the client; ignore and fallback to empty City queryset
elif self.instance.pk:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
class AccountUpdateForm(forms.ModelForm):
class Meta:
model = Account
# fields = '__all__'
fields = ('email',TypeError):
pass # invalid input from the client; ignore and fallback to empty City queryset
elif self.instance.pk:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
views.py
from django.shortcuts import render,redirect
from django.contrib import messages
from django.contrib.auth import login,authenticate
from .forms import AccountForm,AccountUpdateForm
from django.views.generic import TemplateView,ListView,DetailView,CreateView,UpdateView,DeleteView
from django.contrib.auth.decorators import login_required
from .models import Account,City
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginrequiredMixin,UserPassesTestMixin,PermissionrequiredMixin,AccessMixin
class AccountListView(LoginrequiredMixin,ListView):
model = Account
context_object_name = 'accounts'
class AccountDetailView(LoginrequiredMixin,DetailView):
model = Account
def test_func(self):
account = self.get_object()
if self.request.user.email == account.email:
return True
return False
class AccountCreateView(CreateView):
model = Account
form_class = AccountForm
# success_url = reverse_lazy('account_listview')
class AccountUpdateView(LoginrequiredMixin,UpdateView):
model = Account
form_class = AccountUpdateForm
# fields = ('email','image')
# success_url = reverse_lazy('account_detailview')
def form_valid(self,form):
form.instance.user = self.request.user
return super().form_valid(form)
def test_func(self):
account = self.get_object()
if self.request.user.email == account.email:
return True
return False
class AccountDeleteView(LoginrequiredMixin,DeleteView):
model = Account
success_url = '/'
def test_func(self):
account = self.get_object()
if self.request.user.email == account.email:
return True
return False
def load_cities(request):
country_id = request.GET.get('country')
cities = City.objects.filter(country_id=country_id).order_by('name')
return render(request,'users/city_dropdown_list_options.html',{'cities': cities})
# class SocialMediaLoginView(TemplateView):
# template_name = 'users/login.html'
def resend_email_verification(request):
pass
urls.py
from django.urls import path,include
from .views import AccountListView,AccountDetailView,AccountCreateView,AccountUpdateView,AccountDeleteView,resend_email_verification,load_cities
from django.contrib.auth import views as auth_views
from django.conf import settings
from django.conf.urls.static import static
from django.views.static import serve
from .decorators import staff_member_required # from django.contrib.admin.views.decorators import staff_member_required
from django.conf.urls import url,include
urlpatterns = [
path('accounts/',staff_member_required(AccountListView.as_view()),name='account_listview'),path('accounts/register/',AccountCreateView.as_view(),name='account_createview'),path('accounts/<int:pk>/',AccountDetailView.as_view(),name='account_detailview'),path('accounts/<int:pk>/update/',AccountUpdateView.as_view(),name='account_updateview'),path('accounts/<int:pk>/delete/',AccountDeleteView.as_view(),name='account_deleteview'),path('ajax/load-cities/',load_cities,name='ajax_load_cities'),url(r'^oauth/',include('social_django.urls',namespace='social')),#social_django
path('login/',auth_views.LoginView.as_view(template_name='users/login.html'),name='login'),path('logout/',auth_views.logoutView.as_view(template_name='users/logout.html'),name='logout'),path('password_reset/',auth_views.PasswordResetView.as_view(template_name='users/password_reset.html'),name='password_reset'),path('password_reset/done',auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'),name='password_reset_done'),path('password_reset_confirm/<uidb64>/<token>/',auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),name='password_reset_confirm'),path('password_reset_complete',auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'),name='password_reset_complete'),path('verification/',include('verify_email.urls')),path('resend_email_verification/',name='resend_email_verification'),#deneme
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
解决方法
在您的 AccountUpdate 表单中,您写了:
// Set graduationDate to enrollmentDate,then add 4 years
graduationDate = new GregorianCalendar(); // New object
graduationDate.setTime(enrollmentDate.getTime()); // Update time
graduationDate.add(GregorianCalendar.YEAR,4); // add years
但用户可能没有国家/地区,因此将其更改为:
elif self.instance.pk:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。