【问题标题】:Django related_name with _set function带有 _set 函数的 Django 相关名称
【发布时间】:2022-01-23 19:49:51
【问题描述】:

我在我的模型中使用了 related_name 标记,我正在尝试使用 _set 函数过滤我的表单。但是我遇到了这个错误;

  AttributeError: 'Client' object has no attribute 'contact_owner_set'

我认为问题就在这里;

self.fields['contact_owner'].queryset = self.instance.client_owner.contact_owner_set.order_by('name') 

我已尝试删除相关名称字段并将此位更改为;

self.fields['contact_owner'].queryset = self.instance.client_owner.contact_owner_set.order_by('name') 

但是我的其他功能需要related_name。有没有办法解决这个问题?

models.py

from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse

class Client(models.Model):
    name = models.CharField(max_length=100)

    def get_absolute_url(self):
        return reverse("client-detailview", kwargs={"slug": self.slug}) 

    def __str__(self):
        return str(self.name)

class Contact(models.Model):
    client_owner = models.ForeignKey(Client,on_delete=models.CASCADE, related_name='contact_client') # client.contact_client
    name = models.CharField(max_length=100) 

    def get_absolute_url(self):
        return reverse("contact-detailview", kwargs={"slug": self.slug}) 

    def __str__(self):
        return str(self.client_owner) + " - " + str(self.name)

class Action(models.Model):
    client_owner = models.ForeignKey(Client,on_delete=models.CASCADE, related_name='action_client') # client.action_client
    contact_owner = models.ManyToManyField(Contact, related_name='action_contact', blank=True, null=True) # contact.action_contact
    topic = models.CharField(max_length=100, blank=True, null=True)

    def __str__(self):
        return str(self.topic) + " - " + str(self.user_owner) + " - " + str(self.client_owner) + " - " + str(list(self.contact_owner.all().values_list('name', flat=True)))

views.py

from django.shortcuts import render
from django.views.generic import ListView, CreateView, UpdateView
from django.urls import reverse_lazy

from .models import Action, Contact
from .forms import ActionForm

class ActionListView(ListView):
    model = Action
    context_object_name = 'actions'
    template_name = 'crm/action_list.html'

class ActionCreateView(CreateView):
    model = Action
    form_class = ActionForm
    template_name = 'crm/action_form.html' 
    success_url = reverse_lazy('action_changelist')

class ActionUpdateView(UpdateView):
    model = Action
    form_class = ActionForm
    template_name = 'crm/action_form.html'
    success_url = reverse_lazy('action_changelist')

forms.py

from django import forms
from .models import Action, Contact

class ActionForm(forms.ModelForm):
    class Meta:
        model = Action 
        fields = ('client_owner', 'contact_owner', 'topic') 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs) 
        self.fields['contact_owner'].queryset = Contact.objects.none()

        if 'client_owner' in self.data:
            try:
                alan1 = int(self.data.get('client_owner'))
                self.fields['contact_owner'].queryset = Contact.objects.filter(client_owner_id = alan1)
            except (ValueError, TypeError):
                pass
        elif self.instance.pk and self.instance.client_owner: 
            print(self.instance.client_owner)
            print(type(self.instance.contact_owner))
            print(self.instance.contact_owner.values())
            self.fields['contact_owner'].queryset = self.instance.client_owner.contact_owner_set.order_by('name')

【问题讨论】:

    标签: python django forms set


    【解决方案1】:

    related_name 定义了反向关系的名称,所以在你的情况下,没有关系 contact_owner_set 的模型。

    例如,如果要访问客户联系人,则应使用client.contact_client 属性;如果要获取联系人的操作,则必须使用contact.action_contact 属性。

    但是这里没有contact_owner_set的关系:

    self.fields['contact_owner'].queryset = self.instance.client_owner.contact_owner_set.order_by('name') 
    

    self.instance.client_ownerClient 实例,而Client 实例没有contact_owner_set 属性。

    而且您肯定必须使用复数重命名您的 related_name 以提高代码可读性。

    【讨论】:

    • 我明白你的意思,我很清楚。但是我被related_name 字段困住了,我必须出于其他原因使用它。那么,是否有任何其他方法可以使用 _set 方法过滤我的更新视图。
    • 我认为您并不完全理解“使用 _set 方法进行过滤”的含义。当你不指定 related_name 时,Django 使用默认的关系名称。例如,如果您在Contact.client_owner 中没有指定related_name,那么您可以通过反向关系Client.contact_set 访问联系人。如果你指定related_name='contact_client',那么你有Client.contact_client而不是Client.contact_set
    • 所以 Django 中没有任何“_set 方法”过滤,都是通过反向关系访问对象。
    • 您可以阅读更多关于它的信息,例如here
    • 非常感谢您的帮助,总结一下“self.fields['contact_owner'].queryset = self.instance.client_owner.contact_client.order_by('name')”解决了我的问题。
    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多