I wanted to display in success_message new data, changed in my generic UpdateView.
And i dunno how to access those data from form.
Everything is like super standard, code look like that:
class ProductOneUpdateView(UpdateView):
model = ProductOne
fields = ['quantity']
success_message = ................
And i want new quantity, changed by user shown in this success_message.
Looking forward for yours answers!
As the documentation says:
The cleaned data from the form is available for string interpolation using the %(field_name)s syntax.
So if these are form fields, you can write a message like:
class ProductOneUpdateView(SuccessMessageMixin, UpdateView):
model = ProductOne
fields = ['quantity']
success_message = 'The quantity is updated to %(quantity)s'
For more advanced processing of success messages, you can override the get_success_message method [Django-doc], this passes the cleaned_data as parameter, and you can access the (updated) object through self.object:
class ProductOneUpdateView(SuccessMessageMixin, UpdateView):
model = ProductOne
fields = ['quantity']
def get_success_message(self, cleaned_data):
return 'The quantity of {} is updated to {}'.format(
self.object,
self.cleaned_data['quantity']
)
Related
I am trying to solve one issue about saving data in db.
This is an example how I think of it:
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
fieldX = models.SomeFieldType()
#property:
def foo(self):
return self._foo
#foo.setter
def foo(self, var):
self._foo=var
class MyModelForm(models.Modelform):
class Meta:
model = models.MyModel
fields = '__all__'
The thing is I have dict that I am passing to this form (so I am not using view or any provided interaction with user directly. In dict I have some fields and what I want to do is one field that is passed to use it as model property but I do not want it to be saved in db.
So I tried something like:
form = MyModelForm(data_dict)
if form.is_valid():
form.foo = data_dict['data_for_property_not_db']
form.save()
Form does not know that my model has this property.
So basiclly what I want is to write some parts of my data_dict normaly to form and db as always ->works fine
and then I want some data_info pass to that property and use it somewhere in save() as needed without saving it to db itself.
Can you help me with this?
I have a model which the user submits on a form, and I would like to handle that form with a CreateView. However, there is one field in the model which the user doesn't provide, which is their IP address.
The problem is that the CreateView fails with an IntegrityError since the field is empty. I tried modifying request.POST to add the relevant field, but that's not allowed (and a bad idea).
I figured I could use a hidden input on the form and put the IP there but that means the user can blank it or modify it if they like, I want the exact IP that did the POST request.
If I understand correctly both the form_valid and form_invalid methods are too early in the process, since the object hasn't been created yet? Is there any other way of doing this?
Here is what the code looks like:
class Answer(models.Model):
ip_address = models.GenericIPAddressField()
text = models.TextField()
and the view:
class AnswerForm(CreateView):
template_name = "answer.html"
model = Answer
success_url = reverse_lazy('answer')
fields = ['text']
The request data is stored in the object itself, therefore you can access it as such:
class AnswerForm(CreateView):
template_name = "answer.html"
model = Answer
success_url = reverse_lazy('answer')
fields = ['text']
def form_valid(self, form):
form.instance.ip_address = get_ip_address(self.request)
form.save()
return super().form_valid(form)
So to make the above possible I have found out that I have to have ManytoMany Field that is not a problem.
That field is in the form as follows:
class Form(forms.ModelForm):
class Meta:
model = MyModel
fields = ['notes', 'scan']
widgets = {
'scan': forms.CheckboxSelectMultiple(),
}
In the view I have this then:
form = Form(request.POST)
if from.is_valid():
inst = from.save(commit=False)
inst.something = something
inst.save()
Now what do I do, to save the test or scan from the form?
I tried :
inst.test.add(form.cleaned_data['test'])
But that doesn't work for test or scan.
The Model looks like this:
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
notes = models.TextField(default='')
scan = models.ManyToManyField(Scan)
....
Please help I wasn't able find anything in the Internet about this
Thanks!
The documentation of the Form's save method tells it all: If you have a ModelForm that contains the model's ManyToManyField like this:
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['__all__'] # or fields = ['scans'] assuming scans is the M2M field in MyModel
Then you have two ways to save the relationships:
Directly, using form.save()
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data – including many-to-many data – is saved without the need for any additional method calls.
Or indirectly because you want to manipulate the instance before saving:
if form.is_valid():
instance = form.save(commit=False)
instance.some_field = some_value
instance.save()
form.save_m2m() # this saves the relationships
I have a pretty basic definition within my forms.py to pull data from my submitted form. Something I have done with other apps, but for some reason, it is not working at the moment. I feel like I'm overlooking something. Whenever I print(image_height) I get None.
models.py
height_field = models.IntegerField(default=1200)
forms.py
class PostForm(ModelForm):
class Meta:
model = Post
fields = ['user', 'title', 'content', 'post_image',
'height_field', 'width_field', 'draft', 'publish']
def clean_post_image(self):
post_image = self.cleaned_data["post_image"]
image_height = self.cleaned_data.get("height_field")
print(image_height)
return post_image
If you want to validate your form field with respect to other field, you should do that in your clean method.
From the docs,
The form subclass’s clean() method can perform validation that requires access to multiple form fields. This is where you might put in checks such as “if field A is supplied, field B must contain a valid email address”. This method can return a completely different dictionary if it wishes, which will be used as the cleaned_data.
You could do something like this,
def clean(self, cleaned_data):
post_image = cleaned_data.get("post_image")
height_image = cleaned_data.get("height_image")
#do_your_thing
return cleaned_data
I have the following models: Topic, UserProfile, UserSubscribedToTopic
The last of these looks like this:
class UserSubscribedToTopic(models.Model):
topic = models.ForeignKey(Topic)
user_profile = models.ForeignKey(UserProfile)
start_date = models.DateField(null=True, blank=True)
I want to show a list of topics to the user, with a checkbox by each. If the user checks a checkbox then I'll use JavaScript to show the 'start date' text field (so for the purposes of this question I just need to show a text field next to the checkbox). If the user has already saved their selection and is revisiting the page I want to populate the form accordingly when it is first rendered.
I've attempted to do this using formsets:
class SubscribeToTopicForm(ModelForm):
class Meta:
model = UserSubscribedToTopic
fields = ('topic','start_date')
widgets = {'topic': CheckboxInput(attrs={'class': 'topic-checkbox'}),
'start_date': TextInput(attrs={'class': 'date','placeholder': 'Start date'})}
SubscribeToTopicFormSetBase = modelformset_factory(
UserSubscribedToTopic,
form=SubscribeToTopicForm,
extra = 0)
class SubscribeToTopicFormSet(SubscribeToTopicFormSetBase):
def add_fields(self, form, index):
super(SubscribeToTopicFormSet, self).add_fields(form, index)
I almost get what I want if I add the following to my view:
topics_formset = SubscribeToTopicFormSet(queryset=UserSubscribedToTopic.objects.filter(user_profile=user.get_profile()))
However, obviously this will only show the topics to which the user has already subscribed. To show all the topics I really need to do is a LEFT JOIN on the Topic table. I can't see how to do this in Django without resorting to raw.
My questions:
Am I right in thinking it is not possible to specify a queryset for
the formset that is generated from a left join?
Would it be better to
give up on ModelForm and use a formset that I populate manually?
Any better approaches?!
You should create the form on the Topic model, then use the user_set manager to see if the current user has subscribed to the topic.
Once the form is submitted, if any fields are checked, you can then create individual UserSubscribedToTopic objects in your view.
I ended up separating out the checkboxes from the date fields, so I could use a forms.ModelMultipleChoiceField in a Form and a manually-created formset to deal with the date fields.
Here's the code:
Forms:
class SubscribedToTopicForm(ModelForm):
subscribed_to_topic = forms.ModelMultipleChoiceField(required=False,queryset=Topic.available_topics, widget=forms.CheckboxSelectMultiple(attrs={'class': 'topic-checkbox'}))
class Meta:
model = UserProfile
fields = ("subscribed_to_topic",)
def get_checked_topics(self):
return self.cleaned_data['subscribed_to_topic']
class StartDateForm(forms.Form):
topic_id = forms.CharField(widget=forms.HiddenInput,required=False)
start_date = forms.DateField(required=False,label='')
StartDateFormSetBase = formset_factory(form=StartDateForm,extra = 0)
class StartDateFormSet(StartDateFormSetBase):
def get_start_date(self, topic_id):
for i in range(0, self.total_form_count()):
form = self.forms[i]
form_topic_id=long(form.cleaned_data['topic_id'])
if topic_id == form_topic_id:
return form.cleaned_data['start_date']
return ''
View:
GET:
topics_form = SubscribedToTopicForm()
subscribed_to_topic=None
if request.user.is_authenticated():
subscribed_to_topics = SubscribedToTopic.objects.filter(user_profile=request.user.get_profile())
initial_data = []
for topic in Topic.available_topics.all():
start_date=''
if subscribed_to_topics:
for subscribed_to_topic in subscribed_to_topics:
if subscribed_to_topic.topic.id==topic.id:
start_date=subscribed_to_topic.start_date
initial_data.append({'topic_id':topic.id, 'start_date': start_date})
start_date_formset = StartDateFormSet(initial=initial_data)
POST:
start_date_formset = StartDateFormSet(request.POST)
topics_form = SubscribedToTopicForm(request.POST)
start_date_formset.is_valid()
topics_form.is_valid()
for topic in topics_form.get_checked_topics():
start_date = start_date_formset.get_start_date(topic.id)
subscribed_to_topic = SubscribedToTopic()
subscribed_to_topic.topic=topic
subscribed_to_topic.start_date=start_date
subscribed_to_topic.save()