简体   繁体   中英

Django. How to make model choices from another model

I am trying to make migrations for my models:

from django.db import models  
TAKEN = (
    (True, 'Yes'),
    (False, 'No')
)  

class Room(models.Model):
    name = models.CharField(max_length=32)
    number = models.IntegerField()
    taken = models.BooleanField(choices=TAKEN)
    description = models.CharField(max_length=128)

ROOMS_CHOICE = (Room.objects.filter(taken=False))

class Reservation(models.Model):
    date = models.DateField()
    hours = models.IntegerField()
    choice = models.OneToOneField(Room, on_delete=models.CASCADE, choices=ROOMS_CHOICE)

forms for the models:

from django import forms
from .models import TAKEN, ROOMS_CHOICE   
class NewRoomForm(forms.Form):
    name = forms.CharField(label='Name', max_length=32)
    number = forms.IntegerField(label='Room Number')
    taken = forms.ChoiceField(choices=TAKEN, label='Taken', widget=forms.Select)
    description = forms.CharField(label='Description', widget=forms.Textarea)   
class ReservationForm(forms.Form):
    date = forms.DateField(label='Date', widget=forms.SelectDateWidget)
    hours = forms.IntegerField(label='hours', max_value=8)
    choice = forms.ChoiceField(choices=ROOMS_CHOICE, label='room', widget=forms.Select)

When I try to make migrations, an ProgrammingError appears:

django.db.utils.ProgrammingError: (1146, "Table 'conference_room.conference_room' doesn't exist")

I try to make a view where user can book a conference room from a available rooms (those that are not occupied - taken=False). I assume I made some mistakes during building OneToOne relation and writing choices based on the Room model, and that is why the error appeared. How can I rewrite my models and forms?

There are indeed a number of problems here.

The thing causing your issue is not actually your OneToOneField, but the fact that in the definition of ROOMS_CHOICE you are doing a query at module level - so it will be executed when the models file is first imported, before the migration has a chance to run. That sort of thing needs to be done in a method, in this case probably the __init__ of the form (if you need it at all, which you don't - see below).

However there are several more issues. Firstly, you should not be using OneToOne; that implies that a room can only have one reservation, which obviously isn't the case. You need a ForeignKey, which is a one-to-many relation.

Then, you shouldn't use a ChoiceField here. Django includes a field for getting choices from a model: it's called ModelChoiceField, and it takes a queryset:

choice = forms.ModelChoiceField(queryset=Room.objects.filter(taken=False), label='room', widget=forms.Select)

so you in fact don't need to define ROOMS_CHOICE at all.

(I'd also point out that having a taken field on Room doesn't make sense either; a room is only taken at a certain time. You actually need to query for rooms that are not booked at the date/time the reservation is for, which you can't do until the user has actually chosen that date.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM