So I'm thinking that this is not the right way to do things, but I am trying to learn django and I am trying some things out. I am trying to set a foreign key for my Formula model, by hardcoding in an instance of maker.
Models:
class Cooker(models.Model):
name = models.CharField(max_length=20, name="name")
background = models.CharField(max_length=500, name="background")
class Formula(models.Model):
food = models.CharField(max_length=200, name="food")
maker = models.ForeignKey(Cooker, related_name="cooker_key")
Views
class CookerCreate(CreateView):
template_name = "cookercreate.html"
model = Cooker
fields = ['name','background']
success_url = reverse_lazy('cooker')
class FormulaCreate(CreateView):
template_name = "formulahome.html"
model = Formula
fields = ['food']
success_url = reverse_lazy('formulahome')
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.maker = Cooker.objects.get(pk=1)
form.save()
return reverse_lazy('formula home')
In the FormulaCreate class where I am setting self.object.maker, I just want to hard code in a Cooker that I already created. Thanks
EDIT: When I try to submit the form in my FormulaCreate(CreateView) I get the error Exception Value: '__proxy__' object has no attribute 'get'
The reason for your error is that form_valid should return a Response object, and you are returning a URL.
Rather than do this manually you should just call the parent method which will redirect to the success_url that you have already defined:
def form_valid(self, form):
self.object = form.save(commit = False)
self.object.maker = Cooker.objects.get(pk=1)
form.save()
return super(FormulaCreate, self).form_valid(form)
If you are using the post method return redirect('formula home') works too.
Related
Relevant FormView:
class addrecipe(FormView):
form_class = AddRecipeForm
model = Recipe
template_name = 'recipebook/addrecipe.html'
fields = '__all__'
extra_context = {
'recipe_list': Recipe.objects.all()
}
Relevant Form:
class AddRecipeForm(forms.ModelForm):
name = forms.CharField(max_length="50", label="Recipe Name")
description = forms.Textarea(attrs={'class': 'desc-text-area'})
servings = forms.IntegerField()
tools = forms.ModelMultipleChoiceField(queryset=Tool.objects.all(), widget=forms.CheckboxSelectMultiple, required = True, help_text="Select all relevant tools")
class Meta:
model = Recipe
fields = ("__all__")
URL pattern for the details view page:
path('<int:pk>/recipedetails', views.recipedetails.as_view(), name='recipe_details'),
I want to have the user submit the form, then be taken to the details page of the entry they just made into the database. I've tried doing this using reverse/reverse_lazy with a success url but that hasn't been successful.
I also tried adding the following to my form view class:
def get_success_url(self):
test_recipe_id = self.object.id
return reverse('recipeBook:recipe_details', pk=test_recipe_id)
After also changing my path to:
re_path(r'(?P<pk>[^/]+)/recipedetails', views.recipedetails.as_view(), name='recipe_details'),
I get the following Value error:
AttributeError at /recipebook/addrecipe
'addrecipe' object has no attribute 'object'
Your solution was almost there.
You could use the get_success_url method to get the recipe ID after the model. This will allow you redirect with parameters.
class addrecipe(FormView):
form_class = AddRecipeForm
model = Recipe
template_name = 'recipebook/addrecipe.html'
fields = '__all__'
extra_context = {
'recipe_list': Recipe.objects.all()
}
#New method
def get_success_url(self):
test_recipe_id = self.object.id #gets id from created object
return reverse('recipeBook:recipe_details', pk=test_recipe_id)
Your detail url is not receiving the parameter as expected hence it needs to be reconfigured with a new regex
Old:
path('<int:pk>/recipedetails', views.recipedetails.as_view(), name='recipe_details'),
New:
from django.urls import path, re_path
re_path(r'(?P<pk>[^/]+)/recipedetails', views.recipedetails.as_view(), name='recipe_details),
I needed to use HttpResponseRedirect to redirect correctly. My view ended up looking like this:
class addrecipe(FormView):
form_class = AddRecipeForm
model = Recipe
template_name = 'recipebook/addrecipe.html'
fields = '__all__'
extra_context = {
'recipe_list': Recipe.objects.all()
}
def form_valid(self, form):
test_recipe = form.save(commit=False)
test_recipe.save()
test_recipe_id = test_recipe.id
return HttpResponseRedirect(reverse('recipeBook:recipe_details', kwargs={'pk': test_recipe_id}))
Saving the object before grabbing the ID appears to be a necessary step as I found that the ID itself is only created when the object is created.
The reverse return wasn't working, so honestly I hail mary'd a httpresponseredirect in front and it worked. I will update the answer if I figure out why..
I am trying to assign a group to a user but without the need to use the django manager, but I run into a problem and it tells me that "<User: island>" must have a value for the field "id" before this many-to-many relationship can be used.
This is my view:
class UserCreationView(LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, CreateView):
permission_required = 'users.add_user'
login_url = 'users:login'
template_name = 'users/register.html'
model = User
form_class = UserForm
success_message = 'El usuario fue creado exitosamente'
success_url = reverse_lazy('users:user')
def form_valid(self, form):
self.object = form.save(commit=False)
group = Group.objects.get(pk=self.request.POST.get('groups'))
self.object.groups.add(group)
self.object.save()
Simply rearrange order of statements
self.object = self.object.save()
self.object.groups.add(group)
Also there is no need to add instance to object you can just use normal variable instead, and your parameter would be better called group/group_id instead of groups
def form_valid(self, form):
user = form.save()
group = Group.objects.get(pk=self.request.POST.get('group_id'))
user.groups.add(group)
I have the following model in Django which I use to store data about medicines.
class Medicine(models.Model):
Medicine_Name = models.CharField(max_length=100)
User_Associated = models.ForeignKey(User, on_delete=models.CASCADE)
Tablets_In_Box = models.IntegerField()
Dose_in_mg = models.IntegerField()
Dose_Tablets = models.IntegerField()
Number_Of_Boxes = models.IntegerField()
Last_Collected = models.DateField()
def __str__(self):
return self.Medicine_Name
def get_absolute_url(self):
return reverse('tracker-home')
I am trying to create a model form where a user can update the last collection of one of their medicines. Here is what I began with.
class CollectionForm(forms.ModelForm):
class Meta:
model = Medicine
fields = ['Medicine_Name', 'Number_Of_Boxes', 'Last_Collected']
I do not understand how I can call an instance of my model based on the 'Medicine_Name' from the field. In other words, I need the user to be able to select the correct medicine from a dropdown menu, and then the form must update the 'Last_Collected', and 'Numer_Of_Boxes' fields on my Medicine model.
https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#the-save-method
It seems this contains relevant information, but I struggle to see how to use it in this instance. How can I correctly get the instance of the medicine form I need, based on the user input in the form? Furthermore how can I use the save method in my views to make sure the database gets updated correctly?
EDIT Added view for the form:
def update(request, pk):
instance = Medicine.objects.get(id=pk)
if request.method == 'POST':
form = CollectionForm(user=request.user, instance=instance, data=request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.User_Associated = request.user
instance.save()
else:
form = CollectionForm()
context = {'form': form}
return render(request, 'tracker/medicine_collection.html', context )
**EDIT
views:
def update(request, pk):
instance = Medicine.objects.get(id=pk)
if request.method == 'POST':
form = CollectionForm(instance=instance, data=request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.User_Associated = request.user
instance.save()
return redirect ('/')
....
This is based on updating the instance of the specific user. This tutorial helpt me achieve the same thing.
https://youtu.be/EX6Tt-ZW0so
Tried a different approach (class based views - UpdateView) I just learned here on SO. Did not test it but I think its a step in the right direction.
class UpdateMedicine(LoginRequiredMixin, UpdateView):
model = Medicine #call the model you need to update
fields = ['Medicine_Name', 'Number_Of_Boxes', 'Last_Collected'] #specify the fields you need to update
template_name_suffix = 'medicine_update_form' #specify the template where the update form is living
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(
user=self.request.user, #get the current logged in user
instance=get_object_or_404(Medicine, pk=self.kwargs['pk']) #get the pk of the instance
)
return context
def form_valid(self, form):
form.instance.medicine = get_object_or_404(Medicine, slug=self.kwargs['pk'])
return super().form_valid(form) #saves the updates to the instance
def get_success_url(self):
return reverse('medicine-collection') #name of the url where your 'tracker/medicine_collection.html is living
Link the appropriate templates and urls to the above example and try some things yourself.
Link to the django docs:
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-editing/
Good luck!
class PostDetailView(DetailView):
model = Post
template_name = 'detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
instance = Post.objects.get(pk=self.kwargs.get('pk'))
user = instance.post_user
context['comments'] = Comment.objects.filter(comment_post=instance.pk)
context['comments']['profile'] = Profile.objects.get(user=user)
return context
This is my view so far. When i use that code i get this error 'QuerySet' object does not support item assignment. How do i attach the line below correctly?
context['comments']['profile'] = Profile.objects.get(user=user)
The problems is that value of context['comments'] is not a dictionary but QuerySet object.
So you can't do:
context['comments']['profile'] = Profile.objects.get(user=user).
Maybe you can add relation with Profile model right to the Comment model, like:
class Comment(models.Model):
profile = models.ForeignKey(Profile, ...)
...
So then you can have access to the value of Profile who left a comment.
I'm trying to update an model's fields with save method:
forms.py:
class FooForm(forms.ModelForm):
class Meta:
model = Foo
exclude = ['created']
views.py:
class FooView(FormView):
success_url = '/some/url/'
template_name = 'some/template.html'
form_class = FooForm
model = Foo
def form_valid(self, form):
if 'foo' in self.request.session:
pk = self.request.session['foo']
foo = Foo.objects.get(pk=pk)
self.object = form.save(instance=foo)
else:
self.object = form.save()
self.request.session['foo'] = self.object.pk
return HttpResponseRedirect(self.get_success_url())
I have an error, when i try to use form.save(instance=foo):
TypeError at /some/url
save() got an unexpected keyword argument 'instance'
What is my problem?
Django 1.9.0
Python 3.4.3
If you read the very documentation that you linked, you will see that the instance keyword is an input to the ModelForm constructor and not the save method.
You will need to do something like
form = FooForm(instance=foo)
form.save()
You should provide an instance to the constructor of the form, not to save method.
To make it works, you should use UpdateView.
def form_valid(self, form):
if 'foo' in self.request.session:
pk = self.request.session['foo']
foo = Foo.objects.get(pk=pk)
foo_form = self.form_class(form.cleaned_data, instance=foo)
foo_form.save()