【问题标题】:ValueError: <Registration: 749>" needs to have a value for field "id" before this many-to-many relationship can be usedValueError: <Registration: 749>" 需要有一个字段“id”的值才能使用这种多对多关系
【发布时间】:2020-08-08 03:23:50
【问题描述】:

我正在 django 中构建一个比赛注册应用程序,但我无法在 CreateView 通用视图中保存我的模型的 many2many 字段。我从视图中排除了事件字段,因为它允许您选择一个事件,而不是让它从 url 中的 slug 自动生成。我能够使用 get_context_data 方法中的 slug 基于 URL 获取事件对象。我也在 form_valid 方法中尝试了 form.instance.event = event,但它似乎在这里不起作用。我之前没有在 many2many 领域工作过,现在我遇到了麻烦。非常感谢任何帮助。

我收到一个 ValueError: "" 需要为字段 "id" 设置一个值,然后才能使用这种多对多关系。

views.py

​​>
class RegistrationCreateView(CreateView):
    model = Registration

    fields = ['car_year', 'car_manufacture', 'car_model', 'race_number', 'race_class']


    def get_context_data(self, *args, **kwargs):
        slug = self.kwargs['slug']
        event = Event.objects.get(slug=slug)

        context = super().get_context_data(**kwargs)
        context['slug'] = slug
        context['event'] = event
        return context

    def form_valid(self, form):
        form.instance.driver = self.request.user
        try:
            event = Event.objects.get(id=self.request.POST['event'])
        except:
            event = None
        print("test")
        form.instance.event.add(event)

        return super().form_valid(form)

urls.py

​​>
from django.urls import path
from . import views

app_name = "events"
urlpatterns = [
    path(
        route='add/',
        view=views.EventCreateView.as_view(),
        name='add'
    ),
    path(
        route='',
        view=views.EventListView.as_view(),
        name="list"
    ),
    path(
        route='<slug:slug>/',
        view=views.EventDetailView.as_view(),
        name="detail"
    ),
    path(
        route='<slug:slug>/update/',
        view=views.EventUpdateVIew.as_view(),
        name='update'
    ),
    path(
        route="<slug:slug>/register/",
        view=views.RegistrationCreateView.as_view(),
        name='register'
    ),
]

models.py

​​>
from django.db import models
from django.conf import settings

from autoslug import AutoSlugField
from model_utils.models import TimeStampedModel, TimeFramedModel
from localflavor.us.models import USStateField, USZipCodeField
from django.urls import reverse

class Event(TimeStampedModel, TimeFramedModel):
    organizer = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)
    name = models.CharField("Event Name", max_length=255)
    location_name = models.CharField("Event Location", max_length=255)
    location_street_address = models.CharField("Event Address", max_length=100)
    location_state = USStateField("Event State")
    location_city = models.CharField("City", max_length=40)
    location_zip = USZipCodeField("Event Zipcode")
    description = models.TextField("Event Description")
    slug = AutoSlugField("Event Slug",
        unique=True, always_update=False, populate_from="name")
    registration_start = models.DateField("Pre-Registration Starts", blank=True)
    registration_end = models.DateField("Pre-Registration Ends", blank=True)

    def __str__(self):
        return self.name

    def address(self):
        full_location = f"""
        {self.location_name}
        {self.location_street_address}
        {self.location_city}, {self.location_state} {self.location_zip}
        """
        return(full_location)

    def get_absolute_url(self):
        return reverse('events:detail', kwargs={'slug': self.slug})


class Registration(TimeStampedModel):

    class RaceClass(models.TextChoices):
        STOCK_2WD = "S2", "Stock 2 Wheel Drive"
        STOCK_AWD = "SA", "Stock All Wheel Drive"
        PREP_2WD = "P2", "Prepared 2 Wheel Drive"
        PREP_AWD = "PA", "Prepared All Wheel Drive"
        MOD_2WD = "M2", "Modified 2 Wheel Drive"
        MOD_AWD = "MA", "Modified All Wheel Drive"
        CON_2WD = "C2", "Constructors 2 Wheel Drive"
        CON_AWD = "C4", "Constructurs 4 Wheel Drive"

    driver = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    event = models.ManyToManyField(Event)
    car_year = models.PositiveIntegerField("Car Year")
    car_manufacture = models.CharField("Car Manufacture", max_length=15)
    car_model = models.CharField("Car Make", max_length=30)
    race_number = models.PositiveIntegerField("Race Number")
    race_class = models.CharField("Race Class", choices=RaceClass.choices, default=RaceClass.STOCK_2WD, max_length=50)

    def get_absolute_url(self):
        return reverse('events:list')

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

【问题讨论】:

    标签: python django many-to-many django-generic-views


    【解决方案1】:

    您需要先保存表单,因此首先创建要添加多对多对象的对象。只有在创建对象后,您才能向其添加多对多的对象。因此,在您的示例中,您需要执行以下操作:

    def form_valid(self, form):
        form.instance.driver = self.request.user
        if form.is_valid():
            registration = form.save()  # returns the newly created object
    
        registration.event.add(event)
    
        return super().form_valid(form)
    

    【讨论】:

    • 感谢您的解决方案和解释,效果很好。
    • 只要确保你没有保存对象两次,因为你在函数结束时调用了 super().form_valid(form)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-01
    相关资源
    最近更新 更多