I am working on a cookbook website using django and have run into a problem with a foreign key field in my form
the problem is that when i create my recipe i need to have a foreign key pointing to the cookbook that created this recipe but I don't want the user creating the recipe to see the original_cookbook field (they shouldn't have to)
I believe I need to use a widget (HiddenInput) but am I getting confused with the examples given on other sites. Also my friend mentioned something about setting an initial value in the original_cookbook view
tl;dr: I want to point the fk to the users cookbook while keeping the original_cookbook field hidden.
relevant code:
form:
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
model:
class Recipe(models.Model):
def __unicode__(self):
return self.name
original_cookbook = models.ForeignKey(Cookbook)
#cookbooks = models.ManyToManyField('Cookbook', related_name = 'recipes')
name = models.CharField(max_length=200)
author = models.CharField(max_length= 100)
picture = models.ImageField(upload_to = 'Downloads', blank=True)
pub_date = models.DateTimeField('date published', auto_now_add=True, blank=True)
ingredients = models.TextField()
steps = models.TextField()
prep_time = models.IntegerField()
TYPE_CHOICES= (
('SW', 'Sandwich'),
('AP', 'Appetizers'),
('SD', 'Sauces and Dressings'),
('SS', 'Soups and Salads'),
('VG', 'Vegetables'),
('RG', 'Rice, Grains and Beans'),
('PA', 'Pasta'),
('BR', 'Breakfast'),
('MT', 'Meat'),
('SF', 'Seafood'),
('BP', 'Bread and Pizza'),
('DT', 'Desserts'),
)
type = models.CharField(max_length = 2, choices=TYPE_CHOICES)
def index_queryset(self):
return self.objects.all()
view:
def createrecipe(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/index/')
else:
if request.method == 'POST':
form = RecipeForm(request.POST)
if form.is_valid():
recipe = form.save()
user = request.user
cookbooks = user.cookbooks
cookbook = cookbooks.all()[0]
cookbook.recipes.add(recipe)
return HttpResponseRedirect('/account')
else:
form = RecipeForm()
return render_to_response('cookbook/createrecipe.html',
{'form':form},
context_instance=RequestContext(request))
Add exclude = ('original_cookbook',) to your form's Meta class.
Then, in your if form.is_valid() code, do something like:
....
recipe = form.save(commit=False)
recipe.original_cookbook = whatever_that_is
recipe.save()
...
This is answered in the documentation.
from django import forms
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
widgets = {'cookbook': forms.HiddenInput
Related
I want to conditionally display either frequency_input or duration_input fields based on the behavior.recording attribute of the selected behavior.
I have a Trial form that currently displays 3 fields:
behavior_name (foreign Key) dropdown
frequency_input
duration_input
Im not sure if i should the best method to solve this (Javascript or solve in the View)?
Trial Model
class Trial(models.Model):
behavior_name = models.ForeignKey(Behavior, on_delete=models.CASCADE)
client_session = models.ForeignKey(Client_Session, on_delete=models.CASCADE)
frequency_input = models.PositiveIntegerField(default=0, blank=True)
duration_input = models.DurationField(blank=True, default=timedelta(minutes=0))
class Meta:
verbose_name_plural = 'trials'
def __str__(self):
return str(self.id)
Behavior Model
RECORDING_CHOICES = (
('Rate','RATE'),
('Duration','DURATION'),
('Frequency','FREQUENCY')
)
class Behavior(models.Model):
name = models.CharField(max_length=200)
goal = models.CharField(max_length=200)
recording = models.CharField(max_length=10, choices=RECORDING_CHOICES, null=False)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='Active')
def __str__(self):
return self.name
Trial Form
class TrialForm(forms.ModelForm):
class Meta:
model = Trial
fields = ('behavior_name','frequency_input', 'duration_input')
Add Trial View
def add_trial(request, clientsession_id):
client_session = Client_Session.objects.get(id=clientsession_id)
if request.method != 'POST':
form = TrialForm()
else:
form = TrialForm(data=request.POST)
if form.is_valid():
add_trial = form.save(commit=False)
add_trial.client_session = client_session
add_trial.save()
return HttpResponse(status=204, headers={'HX-Trigger': 'trialupdated'})
context = {'client_session': client_session, 'form': form}
return render(request, 'sessions/add_trial.html', context)
i'm new when developing django. I have some question after days by days finding the answer. Here the go.
What i want is making ajax form that handle 2 model form, with 1 submit button
I can already saved the data in each form, but got problem in foreign key field got None instead
Here we go my model:
class ModelA(models.Model):
name = models.CharField(max_length=100, blank=True)
info = models.CharField(max_length=200, blank=True)
def __str__(self):
return self.name
class ModelB(models.Model):
xmodel = models.ForeignKey(to=ModelA, on_delete=models.CASCADE, related_name='modelX', blank=True, null=True)
no_1 = models.CharField(max_length=150, blank=True)
no_2 = models.CharField(max_length=150, blank=True)
Form Class:
class ModelAForm(forms.ModelForm):
class Meta:
model = ModelA
fields = '__all__'
class ModelBForm(forms.ModelForm):
class Meta:
model = ModelB
exclude = ('xmodel',)
View class:
def AddData(request):
tpl = 'add.html'
if request.method == 'POST':
mdla = ModelAForm(request.POST)
mdlb = ModelBForm(request.POST)
if mdla.is_valid():
obj = mdla.save()
if mdlb.is_valid():
mdlb.save(commit=False)
mdlb.xmodel=obj
mdlb.save()
else:
mdla = ModelAForm()
mdlb = ModelbForm()
In TPL i'm using ajax to send, it can save model a and model b, but in modelb xmodel (foreign key) it got None when check in adminpanel.
Which i do wrong, how to make it happen when handling the forms?
For people that got something like me, using 2 form.
i've solved my problem with this logic.
Create object manually
Initiatite form with instance new object
save
for above problem:
def AddData(request):
tpl = 'add.html'
if request.method == 'POST':
mdla = ModelAForm(request.POST)
if mdla.is_valid():
obj = mdla.save()
newObj = ModelB.objects.create(xmodel=obj)
mdlb = ModelBForm(request.POST, instance=newObj)
if mdlb.is_valid():
mdlb.save()
else:
mdla = ModalAForm()
mdlb = ModalBForm
This is solution i get, if anyone could do better please tell me. Thankx
I have a CarRent model that is a ForeignKey to the Car model, on a CarRent detailView after payment i want to alter the CarRent model as well as the Car model, the code works well for the CarRent model, but altering the Car model results in “AttributeError at /car/requests/4/
type object 'Car' has no attribute 'object'” error
class Car(models.Model):
car_owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='car_owner', on_delete=models.CASCADE)
car_model = models.CharField(max_length=20, blank=True, null=True)
rented = models.BooleanField(default=False)
class CarRent(models.Model):
car = models.ForeignKey(Car, related_name='rented_car', on_delete=models.CASCADE)
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='driver_renting', on_delete=models.CASCADE)
active_rent = models.BooleanField(default=False, null=True)
rent_paid = models.BooleanField(default=False)
#login_required
#driver_required(redirect_field_name='app:home')
#csrf_protect
def car_rent_detail_view(request, pk):
object = get_object_or_404(CarRent, id=pk)
# queryset = Car.objects.get(id=pk)
car_object = get_object_or_404(queryset, id=pk)
paystack = PaystackAccount(
settings.PAYSTACK_EMAIL,
settings.PAYSTACK_PUBLIC_KEY,
object.total_cost
)
context = {'object': object, 'pk_public': settings.PAYSTACK_PUBLIC_KEY, 'currency': 'NGN', 'paystack': paystack,
}
if request.method == 'POST':
if paystack.verify_transaction(request.POST['reference']):
messages.success(request, "paystack payment successfull")
car_rented = Car.object.get(pk=pk)
car_rented.rented = True
rent_activation = CarRent.objects.get(pk=pk)
rent_activation.active_rent = True
rent_activation.rent_paid = True
rent_activation.save()
messages.success(request, "Your Rent has successfully being updated")
return render(request, 'app/CarRent_detail.html', context=context)
Any help will be appreciated greatly.
Its a typo, you need to use objects to access manager method, not object. So replace:
car_rented = Car.object.get(pk=pk)
^^^^^^
With:
car_rented = Car.objects.get(rented_car__pk=pk)
You can reverse query from Car model to CarRent via related_name(which is 'rented_car'). More information can be found in documentation.
I have a simple Django 3.1.0 app I need to create in order to assign Tasks with Tags (or assign tags into tasks).
My Model
class Task(models.Model):
user = models.CharField(max_length=33)
time = models.DateTimeField(auto_now_add=True)
task = models.CharField(max_length=500)
tags = models.ForeignKey('Tag', on_delete=models.SET_NULL, null=True)
class Tag(models.Model):
tag = models.CharField(max_length=30, default="No Tag")
members = models.ManyToManyField('Task')
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
My Form
class TaskForm(ModelForm):
class Meta:
model = Task
fields = ['user', 'task', 'tags']
template_name = 'tasks.html'
tags = ModelMultipleChoiceField(
queryset=Tag.objects.values().all(), widget=CheckboxSelectMultiple()
)
My View
def main(request):
model = Task.objects.values().all()
form = TaskForm()
con = {'context': list(model), 'form': form}
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
form.save_m2m()
return redirect('/')
else:
form = TaskForm()
return render(request, "tasks.html", con)
The migrations are successfull, and with the above code, the view shows a checkbox list with the fetched tags, but the problem is that when I hit Submit on the form, the values are not saved/written on the database but the page reloads successfully.
However, if I turn the following:
obj = form.save(commit=False)
form.save_m2m()
into
form.save(commit=True)
#form.save_m2m()
the values are written only from the fields 'user', 'task' - without the 'tags'
It's also funny that what fetches back on the webpage as values of the tags is in the shape of:
[checkbox] {'id': 1, 'tag': 'aks'}
What am I doing wrong? Thanks.
UPDATE after a comment below:
As Abdul Aziz suggested, I had to remove the values() from the queryset. But after that , to make it work, I had to add also:
In the model:
tag = models.CharField(max_length=100, default="No Tags")
and then refer to that one in the form and Vue template.
You have a ForeignKey set to the Tag model on your Task model, when you actually want a ManyToMany relationship between them. Remove the foreign key and set a related_name to the ManyToManyField in the Tag model like so:
class Task(models.Model):
user = models.CharField(max_length=33)
time = models.DateTimeField(auto_now_add=True)
task = models.CharField(max_length=500)
class Tag(models.Model):
tag = models.CharField(max_length=30, default="No Tag")
members = models.ManyToManyField('Task', related_name="tags")
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
Also in your form you have:
tags = ModelMultipleChoiceField(
queryset=Tag.objects.values().all(), widget=CheckboxSelectMultiple()
)
Why are you using values here? Remove it:
tags = ModelMultipleChoiceField(
queryset=Tag.objects.all(), widget=CheckboxSelectMultiple()
)
So I have this project where I have several supervisors that can create projects. I want that for each supervisor they can't make a project with the same title. I tried to use UniqueConstraint but now it's not working. Supervisors can still create a project with the same title. Note: Project's supervisor is automatically assigned to the project creator.
models.py
class Project(models.Model):
title = models.CharField(max_length=100)
due_date = models.DateField()
due_time = models.TimeField()
supervisor = models.ForeignKey(User, default=None, on_delete=models.SET_DEFAULT)
class Meta:
constraints = [models.UniqueConstraint(fields=['title', 'supervisor'], name="unique title")]
verbose_name = "Project"
def __str__(self):
return str(self.title) + "-" + str(self.supervisor)
forms.py
class CreateProjects(forms.ModelForm):
class Meta:
model = models.Project
fields = ['title', 'due_date', 'due_time']
widgets = {
'due_date': DateInput()
}
views.py
#login_required(login_url="/signin")
def create_project(response):
if response.user.is_staff:
if response.method == 'POST':
form = forms.CreateProjects(response.POST, response.FILES)
if form.is_valid():
# save project to db
instance = form.save(commit=False)
instance.supervisor = response.user
print(instance.supervisor)
instance.save()
return redirect('/dashboard')
else:
form = forms.CreateProjects(initial={'supervisor': response.user})
ctx = {'form': form, 'FullName': response.user.get_full_name}
else:
form = "Only Teachers can create projects"
ctx = {'form': form, 'FullName': response.user.get_full_name}
return render(response, "create_project.html", ctx)
The simplest way is to define unique on the field.
class Project(models.Model):
title = models.CharField(max_length=100,unique=True)
repeat on any field(s) you want it to be unique.