Django 用户在主页外注销

问题描述 投票:0回答:1

我有一个 Django 网站。现在的问题是,当我以用户或代理身份登录后,正确的链接仅显示在我的主页上。每当我访问另一个页面时,正确的链接就会消失,并替换为“登录”和“代理登录”。不知何故,用户在主页之外注销。我该如何解决这个问题?预先感谢!

我的模型.py:

class CustomUser(AbstractUser):
    email = models.EmailField(unique=True)
    groups = models.ManyToManyField(Group, related_name='CustomUser_set', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.')
    user_permissions = models.ManyToManyField(Permission, related_name='customuser_set', blank=True, help_text='Specific permissions for this user.')
    is_user = True

class Profile(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    phonenumber = models.IntegerField()

    def __str__(self):
        return f'{self.user.username} Profile'



class Agent(AbstractUser):
    username = models.CharField(max_length=100, unique=True)
    name = models.CharField(max_length=100)
    agent_email = models.CharField(max_length=100, unique=True)
    password = models.CharField(max_length=200)
    image = models.ImageField(upload_to = 'Images/')
    bio = models.TextField()
    instagram = models.URLField(max_length=100)
    twitter = models.URLField(max_length=100)
    facebook = models.URLField(max_length=100)
    linkedin = models.URLField(max_length=100)
    is_featured = models.BooleanField(default = False)
    last_login = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    slug = AutoSlugField(populate_from='name')
    is_staff = models.BooleanField(default=False)
    groups = models.ManyToManyField(Group, related_name='agent_set', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.')
    user_permissions = models.ManyToManyField(Permission, related_name='agent_set', blank=True, help_text='Specific permissions for this user.')
    
    is_agent = True
    USERNAME_FIELD = 'username'
    EMAIL_FIELD = 'agent_email'

    def get_absolute_url(self):
        return reverse('agent-dashboard', kwargs={'slug': self.slug})

    class Meta:
        verbose_name_plural = 'Agents'

    def __str__(self):
        return f'Agent {self.name}'

我的forms.py:

User = get_user_model() 

class UserSignInForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not isinstance(user, User):
            raise forms.ValidationError(
                "This form is for User login only")
        return super().confirm_login_allowed(user)

class AgentSignInForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not isinstance(user, Agent):
            raise forms.ValidationError(
                "This form is for Agent login only")
        return super().confirm_login_allowed(user)

我的后端.py:

User = get_user_model()

class UserAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
        except User.DoesNotExist:
            return None
        
        if user.check_password(password):
            return user
        return None

class AgentAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            agent = Agent.objects.get(Q(username=username) | Q(agent_email=username)) 
        except Agent.DoesNotExist:
            return None
        
        if agent.check_password(password):
            return agent
        return None

我的中间件.py:

class AgentAuthenticationMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if hasattr(request, 'user') and request.user.is_authenticated and isinstance(request.user, Agent):
            request.user = request.user
        response = self.get_response(request)
        return response

我的信号.py:

@receiver(user_logged_in)
def user_logged_in_callback(sender, request, user, **kwargs):
    if isinstance(user, Agent):
        request.user = user

我的 AgentLoginView 和 UserLoginView:

class UserLoginView(LoginView):
    authentication_backend = "users.backends.UserAuthBackend"
    template_name = 'users/login.html'
    form_class = UserSignInForm

    def form_valid(self, form):
        print("Before login, request.user:", self.request.user)
        
        agent = form.get_user()
        # Set the authentication backend before login
        agent.backend = self.authentication_backend
        login(self.request, agent)
        self.request.session['is_agent'] = True
        self.request.session['user_type'] = 'user'
        self.request.session['is_authenticated'] = self.request.user.is_authenticated
        print("After login, request.user:", self.request.user)

        return redirect('home')

class AgentLoginView(LoginView):
    authentication_backend = "users.backends.AgentAuthBackend"
    template_name = 'users/agent_login.html'
    form_class = AgentSignInForm

    def form_valid(self, form):
        print("Before login, request.user:", self.request.user)
        
        agent = form.get_user()
        # Set the authentication backend before login
        agent.backend = self.authentication_backend
        login(self.request, agent)
        self.request.session['is_agent'] = True
        self.request.session['user_type'] = 'agent'
        self.request.session['user_slug'] = agent.slug
        self.request.session['is_authenticated'] = self.request.user.is_authenticated
        print("After login, request.user:", self.request.user)

        return redirect('home')

我的主页视图:

def home(request):
    agents = Agent.objects.all()
    properties = Property.objects.all()

    # Check if the user is authenticated and retrieve user information
    is_agent = request.session.get('user_type') == 'agent'
    user_slug = request.session.get('user_slug')

    # Retrieve the full user object using the stored information
    user = Agent.objects.get(slug=user_slug) if is_agent and user_slug else None
    
    is_authenticated = request.session.get('is_authenticated')
    # Print debugging statements
    print(f"User: {user}")
    print(f"Is Agent: {is_agent}")

    context = {'agents': agents, 'properties': properties, 'is_agent': is_agent, 'user': user, 'is_authenticated': is_authenticated}
    return render(request, 'blog/index.html', context)

我的base.html:

{% if is_authenticated %}
  {% if is_agent %}
    <li><a href="{% url 'agent-dashboard' user.slug %}">Dashboard</a></li>
    <li><a href="{% url 'agent-sign-out' %}">Agent Sign Out</a></li>
  {% else %}
    <li><a href="{% url 'profile' %}">Profile</a></li>
    <li><a href="{% url 'logout' %}">Sign Out</a></li>
  {% endif %}
{% else %}
  <li><a href="{% url 'login' %}">Sign In</a></li>
  <li><a href="{% url 'agent-sign-in' %}">Agent Sign In</a></li>
{% endif %}
django django-models django-views django-templates
1个回答
0
投票

正如已经指出的,这是因为

is_agent
is_authenticated
变量仅由
home
视图设置。由于您在登录时设置会话变量,因此您可以在模板中使用它们:

base.html


{% if request.session.is_authenticated %}
  {% if request.session.user_type == "agent" %}
    <li><a href="{% url 'agent-dashboard' user.slug %}">Dashboard</a></li>
    <li><a href="{% url 'agent-sign-out' %}">Agent Sign Out</a></li>
  {% else %}
    <li><a href="{% url 'profile' %}">Profile</a></li>
    <li><a href="{% url 'logout' %}">Sign Out</a></li>
  {% endif %}
{% else %}
  <li><a href="{% url 'login' %}">Sign In</a></li>
  <li><a href="{% url 'agent-sign-in' %}">Agent Sign In</a></li>
{% endif %}

但是,这是一个黑客实现。您有两个用户对象,我希望您可以看到您正在做很多[不必要的]工作。这变得很难维护。

无需多个用户对象,只需一个具有

User
属性的自定义
is_agent
模型。然后,您的其他类型的用户可以拥有自己的模型,与您的用户具有
OneToOne
关系。

class User(AbstractUser):
    is_agent = False

class Agent(models.Model):
    user = models.ForeignKey(User,..., related_name="agent")
    ... 
    @transaction.atomic
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs) 
        self.user.is_agent = True
        self.user.save(update_fields=["is_agent"]) 

class Regular(models.Model):
    user = models.ForeignKey(User,..., related_name="regular")
    ... 

这样,您只需验证一个用户对象。那么您只需要一张登录表单,一个登录视图,无需自定义身份验证后端。

对于基本模板中的链接:

{% if request.user.is_authenticated %}
  {% if request.user.is_agent %}
    <li><a href="{% url 'agent-dashboard' user.slug %}">Dashboard</a></li>
    <li><a href="{% url 'agent-sign-out' %}">Agent Sign Out</a></li>
  {% else %}
    <li><a href="{% url 'profile' %}">Profile</a></li>
    <li><a href="{% url 'logout' %}">Sign Out</a></li>
  {% endif %}
{% else %}
  {% if request.user.is_agent %} 
  <li><a href="{% url 'agent-sign-in' %}">Agent Sign In</a></li>
  {% else %} 
  <li><a href="{% url 'login' %}">Sign In</a></li>
  {% endif %} 
{% endif %}
© www.soinside.com 2019 - 2024. All rights reserved.