I have a form that displays a drop down for a foreignkey field. The form saves the users selection, however I want the view to update the database entry rather than inserting a new one. Whats the best way to go about this?
Current function:
def formset_valid(self, formset):
self.object = formset.save()
self.object.save()
return HttpResponseRedirect(self.get_success_url())
I have tried something like this:
d = RevisionDefaultType.objects.get(id=1)
n = RevisionSettings.objects.get(self.object)
d.defaultrevisiontype = n
d.save()
But it throws an error that the data being updated is not an instance.
I managed to tweak the update example from https://docs.djangoproject.com/en/dev/topics/db/queries/#saving-foreignkey-and-manytomanyfield-fields. This seems to be working as desired.
def formset_valid(self, formset):
self.object = formset.save(commit=False)
revdefault = RevisionDefaultType.objects.get(pk=1)
revget = RevisionSettings.objects.get(global_revision_type=self.object)
revdefault.defaultrevisiontype = revget
revdefault.save()
return HttpResponseRedirect(self.get_success_url())
Thanks again for the help.
You must add force_update=True to your save() function.
For more info about How Django knows to UPDATE vs. INSERT see this link in django's documentation.
Related
I apologize for my confusing title but I hope the code explains it better.
In my views.py file I have the follow view
def create_view(request):
context = {}
form = CreateForm(request.POST)
if request.method == "POST":
if form.is_valid():
instance = form.save(commit=False)
instance.author = request.user
instance.save()
instance.author.profile.participating_in = Post.objects.get(
title=instance.title
)
instance.save()
print(instance.author.profile.participating_in)
context["form"] = form
return render(request, "post/post_form.html", context)
when I print out the value of instance.author.profile.participating_in it shows up in my terminal however when I check the admin page it doesnt update at all. I'm sure I messed up somewhere silly but I cant seem to find it. Thanks!
participating_in is the profile model field, but you are not calling the save() method for profile anywhere.
You have to do it like the following:
profile = instance.author.profile
profile.participating_in = Post.objects.get(title=instance.title)
profile.save()
If participating_in is ManyToManyField then we can do it like this:
post = Post.objects.get(title=instance.title)
instance.author.profile.participating_in.add(post)
Note that add(), create(), remove(), clear(), and set() all
apply database changes immediately for all types of related fields. In
other words, there is no need to call save() on either end of the
relationship.
Look at Related objects reference
I have a django form that has a multiple choice field. The field should be dynamic, that is, only the records associated with the user who is currently logged in should be displayed. I've managed to put this together so far;
forms.py
class myForm(forms.ModelForm):
def __init__(self, someUser, *args, **kwargs):
super(myForm, self).__init__(*args, **kwargs)
someRecords = models.SomeModel.objects.filter(someUser = someUser)
#The line above gets records associated with a specific user
displayNames = []
for i in someRecords:
displayNames.append((i.someField, i.someOtherField + ' ' + i.someOtherField2))
#I am basically making a list of tuples, containing a field and a concatnation of two other fields. The latter will be what is displayed in the select box
self.fields['theSelectField'] = forms.ChoiceField(choices = displayNames)
class Meta:
#I defined model, fields and labels here
views.py
def myFormPage(request):
someUser = request.user.someextensionofuser.someUser
form = forms.myForm(someUser)
context = {'form': form}
if request.method == 'POST':
form = forms.myForm(someUser, data = request.POST)
if form.is_valid():
#Do Stuff if form is valid. However,this stuff doesn't get done, the page refreshes instead
So I've managed to make the select options dynamic. However, now I can't submit data.
EDIT: One of the comments helped me solve the previously stated problem. I've updated the views.py code. However, now I'm running into this error;
Cannot assign "'someString'": "someModel.someField" must be a
"someForeignModel" instance
The option values seem to be strings instead of references to objects. How do I solve this?
This limits the possible options of your select field:
self.fields['theSelectField'].queryset = SomeModel.objects.filter(someUser = someUser)
In your views you might want to use a Class Based View, because it handles a lot of stuff automatically and saves you time. Take a look here: https://ccbv.co.uk/
I firgured it out. Since my main problem was with how the options are displayed to a user, I decided to go with changing my str method in models.py to;
class someModel(models.Model):
#my fields
def __str__(self):
return self.someField + ' ' + self.someOtherField
Then in my forms.py, I went with #dmoe's answer;
self.fields['theSelectField'] = forms.ModelChoiceField(queryset = models.SomeModel.objects.filter(someUser = someUser))
So now both problems are solved. My options have custom labels, and I can submit my data without running into valueError.
I tried saving data on database using django views but it return a error.
def get_enroll(request, pk):
user = request.user
users = User.objects.filter(username=user)
course = Course.objects.filter(pk=pk)
chapter = ChapterModel.objects.filter(course = course)
abc = Enroll()
abc.save_enroll(users, course, chapter)
template_name = 'dashboard.html'
context = {'users':user,'course':course}
return render(request, template_name, context)
You can save it directly like:
Enroll(user=user, course=course, chapter=chapter).save()
You can simply use:
abc = Enroll.objects.create(users=users, course=course, chapter=chapter)
Since you havent provided your models, nor any logic of how you want this to work, I cannot give you a better solution than this one.
Hope this helps
Hey All I am using Django 1.10.7
I am creating a form that creates a store location to a store. Now what I want to happen is to have the store already associated with the store location when the form is loaded.
The url has the proper id of the foreign key of the store ex: localhost:8000//office/dealer/1/location/create. and I see that that the store key is in the request keyword arguments. But I can't get how to associate that into the form. Any help would be really appreciated
Here is how I have my code
#views.py
class DealerLocationCreateView(CreateView):
model = models.DealerLocation
fields = ['dealer'
'dealer_location_name',
'dealer_location_mailing_address',
'dealer_location_mailing_city',
'dealer_location_mailing_state',
'dealer_location_mailing_zipcode',
'dealer_location_mailing_phone',
'dealer_location_shipping_address',
'dealer_location_shipping_city',
'dealer_location_shipping_state',
'dealer_location_shipping_zipcode',
'dealer_location_shipping_phone'
]
def form_valid(self, form):
form.instance.dealer = self.request.dealer_pk
return super(DealerLocationCreateView, self).form_valid(form)
-
# urls.py
url(r'^dealer/(?P<dealer_pk>\d+)/location/create', DealerLocationCreateView.as_view(), name='new-location'),
Why not using :
def form_valid(self, form):
pk = self.kwargs.get("dealer_pk", None)
form.instance.dealer = pk
return super(DealerLocationCreateView, self).form_valid(form)
So, I'm using Django's Model Formset to produce sets of forms for different data. It is working great, but I want to add a feature where when a user displays the formset and, say, updates 2 out of the 10 items, I can track just the 2 updated, and output a message like "You have updated 2 items" kind-of-thing.
Do Django Model Formsets have a built in API for this? I can't seem to find it on the Django Docs.
I've tried various approaches but keep getting this when using the code offered by Peter below:
'Attendance' object has no attribute 'has_changed.'
If I switch form.has_changed to formset.has_changed(), I get
'list' object has no attribute 'has_changed'
My View and Post method
class AttendanceView(TemplateView):
template_name = 'example.html'
def changed_forms(self, formset):
return sum(1 for form in formset if form.has_changed())
def post(self, request, *args, **kwargs):
formset = AttendanceFormSet(request.POST)
if formset.is_valid():
formset = formset.save()
forms_changed = self.changed_forms(formset)
context = self.get_context_data(**kwargs)
context['total_changed_forms'] = forms_changed
return self.render_to_response(context)
else:
return HttpResponse("POST failed")
So I figured it out, just change:
formset = formset.save()
to
formset.save()
Formsets have a has_changed method which will report whether or not any of its forms have been changed. That's not exactly what you're looking for, but if you look at its implementation it should show you how to do it. That method is:
def has_changed(self):
"""
Returns true if data in any form differs from initial.
"""
return any(form.has_changed() for form in self)
So you can count changed forms with:
def changed_forms(formset):
return sum(1 for form in formset if form.has_changed())
Or if you're comfortable using the integer meanings of boolean values:
return sum(form.has_changed() for form in formset)
I personally find that unappealing compared to the more explicit mapping from true to 1, but opinions differ there.