How get instance in a method clean from some forms - python

How can I get the Article instance in my model form's clean method? I tried too access self.instance but it is None. How do I get the previous field values?
model
class Article(models.Model):
name = models.CharField(max_length=25)
value = models.CharField(max_length=25)
forms
class ArticleForm(forms.ModelForm)
class Meta:
model = Article
fields = '__all__'
def clean(self):
cleaned_data = super().clean()
get_instance = self.instance
print(get_instance) and I get None
views
def test(request)
form = ArticleForm({'name':'test', 'value':'test'})
if form.is_valid():
print(1)
else:
print(form.errors)

You get None because you didn't instantiate the form with an instance.
form = ArticleForm({'name':'test', 'value':'test'})
If you instantiate the form with an instance, then you can access it with self.instance in the clean method.
article = Article.objects.get(pk=1)
form = ArticleForm({'name':'test', 'value':'test'}, instance=article)
However, note that cleaning the form alters the model instance. If you want the original values, you should refetch the instance from the database, e.g. original_instance = Art
def clean(self):
cleaned_data = super().clean()
if self.instance is not None and self.instance.pk is not None:
original_instance = Article.objects.get(pk=self.instance.pk)
else:
original_instance = None
...
If you only want to know which fields changed, and don't care about their original values, it would be simpler to use the changed_data attribute.

Related

how can i save some information that i got in views to one of fields in models - django

this is my views.py :
i want save type in device field in model
class GetDeviceMixin( object):
def setup(self, request, *args, **kwargs):
super().setup( request, *args, **kwargs)
type= request.META['HTTP_USER_AGENT']
print(type)
return type
class RegisterView(GetDeviceMixin , generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy("register")
template_name = "man/man.html"
and this is my models.py
class account(AbstractBaseUser):
first_name= models.CharField(max_length=20,verbose_name="first name")
device = models.CharField(verbose_name="device" , max_length=100)
this is my forms.py:
class GetReq(forms.ModelForm):
class Meta:
model = account
fields = ['device',]
First, pop Classy CBVs onto your browser bookmark list ...
I'm assuming that you want to use a form, either to get other information from the user, or to allow the user to override the automatically determined value of device. In this case, you want to pass it as the initial value for device to the form
Now, look at CreateView to work out what to subclass. get_initial() looks hopeful, so
def get_initial(self):
initial = super().get_initial()
initial['device'] = self.device_type # as per the comment!
return initial
You should now see a form with the automatically determined value as the default value
If the intent was to get other fields of the model from the user and to always forcibly insert the automatically determined device_type, you would instead subclass form_valid
def form_valid(form):
obj = form.save( commit=False)
obj.device = self.device_type
obj.save()

Differentiate object vs instance

Some consider model as an object, some consider as an instance. Can anyone tell me what is the difference between these two examples?
model.py:
class ToDo(models.Model):
name = models.CharField(max_length=100)
due_date = models.DateField()
def __str__(self):
return self.name
forms.py:
class ToDoForm(forms.ModelForm):
class Meta:
model = ToDo
fields = ['name', 'due_date']
views.py:
def todo_list(request):
todos = ToDo.objects.all()
context = {'todo_list': todos}
return render(request, 'todoApp/todo_list.html', context)
Considering the code below, what is form instance?
class PostDetailView(DetailView):
model = Post
def post(self, *args, **kwargs):
form = CommentForm(self.request.POST)
if form.is_valid():
post = self.get_object()
comment = form.instance
comment.user = self.request.user
comment.post = post
comment.save()
return redirect('detail', slug=post.slug)
return redirect('detail', slug=self.get_object().slug)
So in object-oriented programming, an object is an instance of a class. So model instance and model object are the same.
Let's do an example for that:
# This is your class
class ToDo(models.Model):
name = models.CharField(max_length=100)
due_date = models.DateField()
# If somewhere I call
my_var = ToDo() # my_var contain an object or an instance of my model ToDo
As for your question about the form, each form in Django may or may not contain an instance. This instance is the object modified by the form. When you create an empty form, this form.instance is None, because your form is not bound to an object. But if you build a form taking an object to modify as its parameter or after filling it, this object is the instance.
Example:
form = CommentForm()
print(form.instance) # This will return None, there is no instance bound to the form
comment = Comment.objects.get(pk=1)
form2 = CommentForm(instance=comment)
print(form2.instance) # Now the instance contain an object Comment or said an other way, an instance of Comment. When you display your form, the fields will be filled with the value of this instance
I hope that it's a little bit more clear.
CommentForm is ModelForm and ModelForm has instance attribute (which you can set (update scenario) or __init__ method of CommentForm will instantiate new model instance of model that you set to Metaclass
from BaseModelForm source:
if instance is None:
# if we didn't get an instance, instantiate a new one
self.instance = opts.model()
object_data = {}

Set values for form field by query using filter

I want to set the item in dropdown using the query in the form. I want to add employee and the select company which using filter Is_Del= 0. I do not know how to set values for the drop down and where to write this query.
I tried to put in Forms.py, but it is not working.
This is form.py
class EmployeeCreateForm(forms.ModelForm):
class Meta:
model = Employee
fields = ('Emp_Name','Emp_company','Emp_Dept','Emp_Join_Date', 'Emp_End_Date')
def clean(self):
cleaned_data = super(EmployeeCreateForm, self).clean()
Emp_Name = cleaned_data.get('Emp_Name')
Emp_company = cleaned_data.get('Emp_company')
Emp_Dept = cleaned_data.get('Emp_Dept')
Emp_Join_Date = cleaned_data.get('Emp_Join_Date')
Emp_End_Date = cleaned_data.get('Emp_End_Date')
return cleaned_data
def __init__(self, *args, **kwargs):
super(EmployeeCreateForm,self).__init__(*args, **kwargs)
self.fields['Emp_company'].queryset = Company.objects.filter(Is_Del=0)
and below is my view.py
class EmployeeCraeteView(LoginRequiredMixin,SuccessMessageMixin,CreateView):
model=Employee
form = EmployeeCreateForm
success_message = " Employee Craeted successfully!"
success_url="../../company/all-companies"
template_name = 'employee_form.html'
fields =[
'Emp_Name','Emp_company','Emp_Dept','Emp_Join_Date',
'Emp_End_Date'
]
companies= Company.objects.filter(Is_Del=0)
def form_valid(self,form):
form.instance.Emp_Crt_By = self.request.user
if form.cleaned_data['Emp_Join_Date'] >= form.cleaned_data['Emp_End_Date']:
form.add_error('Emp_End_Date', 'Joining date should be less than Ending date')
return self.form_invalid(form)
return super(EmployeeCraeteView, self).form_valid(form)
I want to show only this companies in the form which are filtered by Is_Del =0
Your EmployeeCreateView is wrong:
Remove the attributes form, fields and companies
Add form_class = EmployeeCreateForm.
The reason is that form doesn't do anything in a CreateView (see here). To use a custom form class, you need to pass it to form_class.
Your CreateView was dynamically creating the form using a modelform_factory with the fields you defined (if you hadn't added those you'd have seen your mistake immediately) and so your EmployeeCreateForm is never instantiated.

How to use extra field from modelForms to query an object? Django

I have the following form:
class Recipe_IngredientForm(forms.ModelForm):
class Meta:
model = Recipe_Ingredient
fields = ('quantity', 'quantityUnit')
def __init__(self, *args, **kwargs):
super(Recipe_IngredientForm, self ).__init__(*args, **kwargs)
self.fields['ingredient_form'] = forms.CharField()
And I'm trying to get the value of this form to search for an object, if it exists, i'll set it to be saved in my model.
def recipe_add_ingredient(request, pk):
recipe = get_object_or_404(Recipe, pk=pk)
if request.method == "POST":
form = Recipe_IngredientForm(request.POST)
if form.is_valid():
recipeIngredient = form.save(commit=False)
recipeIngredient.recipe = recipe
aux = form.fields['ingredient_form']
recipeIngredient.ingredient = Ingredient.objects.get(name=aux)
recipeIngredient.save()
return redirect('recipe_detail', pk=recipe.pk)
else:
form = Recipe_IngredientForm()
return render(request, 'recipe/recipe_add_ingredient.html', {'form': form})
But I get an error when submitting the form: Ingredient matching query does not exist, but it shows that I'm getting a value that exists via GET, and if I query the exact same thing in the shell, it return my object. Any Idea?
You should be accessing cleaned_data, not fields.
aux = form.cleaned_data['ingredient_form']
Also note, you should define that field at class level, then you don't need to define __init__ at all.
class Recipe_IngredientForm(forms.ModelForm):
ingredient_form = forms.CharField()
class Meta:
model = Recipe_Ingredient
fields = ('quantity', 'quantityUnit')

Setting model data after validation

I'm trying to set data in a FormModel after validation. Example of a use case here is if I want to assign a unique number to a form data set if and only if it passes validation. There's some other information I'm trying to tack on too that isn't available prior to validation. I've tried setting in both the view class and in the clean() method of the ModelForm but can't seem to get it right. Each time I get an exception saying that "tag_id" cannot be null. Obviously I'm not setting it in a way that let's form.save() access the data.
Note that in the example below I'm trying to set tag_id in two places to illustrate what I've tried; obviously only one place would be needed if it worked.
What is the proper way to do this?
Model and FormModel:
class Video(models.Model):
tag_id = models.BigIntegerField()
name = models.CharField(max_length=200)
uploaded = models.DateTimeField()
size = models.BigIntegerField()
video_file = models.FileField(upload_to='documents/%Y/%m/%d')
class Meta:
db_table = 'videos'
class VideoForm(forms.ModelForm):
class Meta:
model = Video
fields = ['name', 'video_file']
def clean(self):
self.data['tag_id'] = 10
return self.cleaned_data
The view class:
class Upload(FormView):
template_name = "account/templates/upload.html"
form_class = VideoForm
success_url = reverse_lazy('account:home')
def form_valid(self, form):
form.cleaned_data['tag_id'] = 10
form.save()
return super().form_valid(form)
Exception on form.save():
IntegrityError at /account/upload/
(1048, "Column 'tag_id' cannot be null")
You should set the attribute of the model instance:
form.instance.tag_id = 10
form.save()

Categories

Resources