social django 'NoneType' 对象没有属性 'city_set'
social django 'NoneType' object has no attribute '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, email, 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, email, username, password):
user = self.create_user( #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
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, blank=True, null=True)
first_name = models.CharField(max_length=100, blank=True, null=True)
last_name = models.CharField(max_length=100, blank=True, null=True)
GENDER_LIST=(
('Male', 'Male'),
('Female', 'Female')
)
gender = models.CharField(max_length=100, choices=GENDER_LIST, blank=True, null=True)
birthday = models.DateField(help_text='Kindly provide a global date formatting as follows: (YYYY-MM-DD)', auto_now=False, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, blank=True, null=True)
city = models.ForeignKey(City, on_delete=models.SET_NULL, blank=True, null=True)
district = models.CharField(max_length=100, blank=True, null=True)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
slug = models.SlugField(max_length=200, blank=True, 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, *args, **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','username','company','phone','first_name','last_name','gender','birthday','country','city','district','image')
def __init__(self, *args, **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')
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, UserPassesTestMixin, 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, UserPassesTestMixin, UpdateView):
model = Account
form_class = AccountUpdateForm
# fields = ('email','username', 'company','phone','first_name','last_name','gender','birthday','country','city','district','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, UserPassesTestMixin, 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/', resend_email_verification, name='resend_email_verification'), #deneme
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
在您的 AccountUpdate 表单中您写了:
elif self.instance.pk:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
但用户可能没有国家,所以将其更改为:
elif self.instance.pk and self.instance.country:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
如果我使用 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, email, 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, email, username, password):
user = self.create_user( #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
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, blank=True, null=True)
first_name = models.CharField(max_length=100, blank=True, null=True)
last_name = models.CharField(max_length=100, blank=True, null=True)
GENDER_LIST=(
('Male', 'Male'),
('Female', 'Female')
)
gender = models.CharField(max_length=100, choices=GENDER_LIST, blank=True, null=True)
birthday = models.DateField(help_text='Kindly provide a global date formatting as follows: (YYYY-MM-DD)', auto_now=False, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, blank=True, null=True)
city = models.ForeignKey(City, on_delete=models.SET_NULL, blank=True, null=True)
district = models.CharField(max_length=100, blank=True, null=True)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
slug = models.SlugField(max_length=200, blank=True, 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, *args, **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','username','company','phone','first_name','last_name','gender','birthday','country','city','district','image')
def __init__(self, *args, **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')
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, UserPassesTestMixin, 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, UserPassesTestMixin, UpdateView):
model = Account
form_class = AccountUpdateForm
# fields = ('email','username', 'company','phone','first_name','last_name','gender','birthday','country','city','district','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, UserPassesTestMixin, 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/', resend_email_verification, name='resend_email_verification'), #deneme
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
在您的 AccountUpdate 表单中您写了:
elif self.instance.pk:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')
但用户可能没有国家,所以将其更改为:
elif self.instance.pk and self.instance.country:
self.fields['city'].queryset = self.instance.country.city_set.order_by('name')