当用户注册时,我想将他们的国家/地区添加到他们的个人资料中。但是,该字段在数据库中仍为空白,并且不会填充国家/地区。我是 Django 中的身份验证新手,因此其他方面可能是错误的。我认为顺序可能是问题所在?我真的不确定。
Views.py
def get_country(ip):
if ip in ['127.0.0.1', 'localhost', '::1']:
return 'Localhost'
# Perform GeoIP lookup
g = GeoIP2()
try:
result = g.city(ip)
country = result["country_name"]
except Exception as e:
print(f'Error: {e}')
country = "Unknown"
return country
def signup_view(request):
if request.method == 'POST':
form = UserCreateForm(request.POST)
if form.is_valid():
user = form.save()
# Get the user's IP address
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0].strip()
else:
ip = request.META.get('REMOTE_ADDR')
# Determine the user's country
country = get_country(ip)
# Create the profile with the country information
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
Profile.objects.create(user=user, country=country)
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('/')
else:
form = UserCreateForm()
return render(request, 'signup.html', {'form': form})
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(
default='profile_pics/default.jpg', upload_to='profile_pics')
country = models.CharField(max_length=100)
def __str__(self):
return f'{self.user.username} Profile'
@receiver(post_save, sender=User)
def manage_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.get_or_create(user=instance)
我已经使用 RequestFactory() 在 shell 中运行了 get_country 函数,并且根据 ip 获得了正确的国家/地区。所以,这个功能还是不错的。它正在注册期间更新国家/地区的个人资料,但这是行不通的。
问题在于你创建了 两次 用户资料:
-
在
signup_view
中: 在这里,你明确地创建了Profile
实例,但这发生在用户登录之前。 -
在
manage_profile
信号接收器中: 当post_save
信号被触发时,此函数会为每个新创建的用户创建一个Profile
实例。
由于你在
signup_view
中没有将用户保存到数据库,因此
manage_profile
信号接收器创建了一个新的、空的
Profile
实例,而这个实例没有包含任何国家/地区信息。
为了解决这个问题,你应该在
signup_view
中创建
Profile
实例
之后
立即保存用户:
def signup_view(request):
# ... existing code ...
# Create the profile with the country information
Profile.objects.create(user=user, country=country)
# Save the user to the database
user.save()
# Authenticate and log in the user
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('/')
# ... existing code ...
通过这样做,
post_save
信号将会检测到一个已经存在的
Profile
实例,并且不会创建新的实例。
另外,你也可以完全删除
manage_profile
信号接收器,并在
signup_view
中处理所有用户资料创建逻辑,因为你已经在明确地创建它了。