Queryset from non-related model in __init__ modelform method - django

I have two model classes. They are not related models (no relationship).
# models.py
class Model1(models.Model):
description = models.TextField()
option = models.CharField(max_length=64, blank=False)
def __str__(self):
return self.option
class Model2(models.Model):
name = models.CharField(max_length=64, blank=False)
def __str__(self):
return self.name
I have respective form from where I am submitting and saving data in my table. I want to use my Model2 data to fill-in 'option' field as select field, so I am introducing below init method.
# forms.py
class Model1Form(forms.ModelForm):
def __init__(self, *args, **kwargs):
all_options = Model2.objects.all()
super(Model1Form, self).__init__(*args, **kwargs)
self.fields['option'].queryset = all_options
class Meta:
model = Model1
fields = ('description', 'option')
It does not render the dropdown on my template, so I am wondering whether it is right way to address the issue (acknowledging that models are not related to each other).

Related

Cannot assign "id": "Product.category" must be a "CategoryProduct" instance

i'm working on a django project and i got this error (Cannot assign "'11'": "Product.category" must be a "CategoryProduct" instance.) anyone here can help me please.
Model:
class Product(models.Model):
name = models.CharField("Nombre", max_length=150)
category = models.ForeignKey(CategoryProduct, on_delete=models.SET_NULL, null=True, related_name='category')
def __str__(self):
return self.name
View:
class ProductCreateView(CreateView):
model = Product
form_class = ProductForm
success_url = '/adminpanel/products/'
def post(self, request, *args, **kwargs):
form = self.get_form()
category = CategoryProduct.objects.get(id=request.POST['category'])
if form.is_valid():
product = form.save(commit=False)
product.category = category
product.save()
Form:
class ProductForm(forms.ModelForm):
name = forms.CharField(max_length=150, label="Nombre")
category = forms.ChoiceField(choices=[(obj.id, obj.name) for obj in CategoryProduct.objects.all()], label="Categoría")
class Meta:
model = Product
fields = ['name', 'category']
You can let Django's ModelForm do its work, this will create a ModelChoiceField [Django-doc], which is where the system gets stuck: it tries to assign the primary key to category, but that should be a ProductCategory object, so you can let Django handle this with:
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'category']
If you want to specify a different label, you can use the verbose_name=… [Django-doc] from the model field, or specify this in the labels options [Django-doc] of the Meta of the ProductForm. So you can specify Categoria with:
class Product(models.Model):
name = models.CharField('Nombre', max_length=150)
category = models.ForeignKey(
CategoryProduct,
on_delete=models.SET_NULL,
null=True,
related_name='products',
verbose_name='Categoria'
)
def __str__(self):
return self.name
then the CreateView can just use its boilerplate logic:
class ProductCreateView(CreateView):
model = Product
form_class = ProductForm
success_url = '/adminpanel/products/'
Note: The related_name=… parameter [Django-doc]
is the name of the relation in reverse, so from the Category model to the Product
model in this case. Therefore it (often) makes not much sense to name it the
same as the forward relation. You thus might want to consider renaming the category relation to products.

changing django model filed data before saving to database

i want to update model field data before saving to database.
class mynumber(TimeStampedModel):
text = models.TextField(max_length=10000, null=True, blank=True)
number = models.DecimalField(default=0, max_digits=9, decimal_places=2)
#serializer file
class mynumberSerializer(serializers.ModelSerializer):
class Meta:
model = mynumber
fields = "__all__"
#view
class mynumberViewSet(CreateListMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
serializer_class = mynumberSerializer
queryset = mynumber.objects.all()
i want to divide number field by 2 before saving to database.
what should be the best approach?
One approach is overriding the def save() method of your model class mynumber.
def save() method is going to run when example_object.save() is invoked on an object and you can access it's fields like this before saving into database. So you can override the save() method of your model,
class Example(models.Model):
text= models.TextField(null=True, blank=True)
number = models.DecimalField(max_digits=None, decimal_places=None)
def save(self, *args, **kwargs):
self.number = self.number / 2
super(Example, self).save(*args, **kwargs)

rendering foreign field in django form

I have a model where a field references a foreign key from another model as:
class DummyModel(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=150)
image_type = models.ForeignKey(ImageTypeModel) # Foreign key
class Meta:
db_table = "dummy"
The parent model is also simple:
class ImageTypeModel(models.Model):
name = models.CharField(max_length=100)
dims = models.IntegerField()
class Meta:
db_table = "imagetypes"
Now, I attempt to render a record in a form and for that purpose I am using django-crispy-forms. So, I have:
class DummyForm(ModelForm):
class Meta:
model = DummyModel
fields = ['name', 'description', 'image_type']
def __init__(self, *args, **kwargs):
super(DummyForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-sm-2'
self.helper.field_class = 'col-sm-10'
#self.helper.form_tag = False
self.helper.layout = Layout(
Field('name'),
Field('description'),
Field('image_type'))
The image_type field renders as a drop-down list which is perfect but instead of the name of the image types, the entries are all labelled ImageTypeModel. Is there a mechanism so that I can display the corresponding name from the ImageTypeModel record but when the form is saved it saves the primary key rather than the name.
You should implement the __unicode__ (python 2) or __str__ (python 3) method inside the model.
Like this:
class ImageTypeModel(models.Model):
name = models.CharField(max_length=100)
dims = models.IntegerField()
class Meta:
db_table = "imagetypes"
# For Python 2
def __unicode__(self):
return self.name
# For Python 3
def __str__(self):
return self.name

django manytomany field using through and formwizard

I am trying to create a pretty complicated form and break it up using formwizard. The first thing I am trying to do is get the ManyToManyField using through to display, Then I need to figure out how to make it all save.
#models.py
----------------------
class Meat(models.Model):
name = models.charField(max_length=200)
company = models.CharField(max_length = 200)
class Starch(models.Model):
name = models.CharField(max_length=200)
company = models.CharField(max_length=200)
class Recipe(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(help_text='Please describe the finished dish')
meat = models.ManyToManyField('Meat' through='RecipeMeat')
meat_notes = models.TextField()
starch = models.ManyToManyField('Starch' through='RecipeStarch')
starch_notes = models.TextField()
class RecipeMeat(models.Model):
recipe = models.ForeignKey(Recipe)
meat = models.ForeignKey(Meat)
qty = models.FloatField()
class RecipeStarch
recipe = models.ForeignKey(Recipe)
starch = models.ForeignKey(Starch)
qty = models.FloatField()
.
#forms.py
-------------------
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ('name', 'description')
class RecipeMeatForm(forms.ModelForm):
class Meta:
model = RecipeMeat
class RecipeMeatNotesForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ('meat_notes',)
class RecipeStarch(forms.ModelForm):
class Meta:
model = RecipeStarch
class RecipeStarchNotesForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ('starch_notes')
MeatFormSet = inlineformset_factory(Recipe, RecipeMeat, form=RecipeMeatForm, extra=1)
.
#views.py
---------------------------
class CreateRecipeWizard(SessionWizardView):
template_name = "create-recipe.html"
instance = None
file_storage = FileSystemStorage(location= 'images')
def dispatch(self, request, *args, **kwargs):
self.instance = Recipe()
return super(CreateRecipeWizard, self).dispatch(request, *args, **kwargs)
def get_form_instance( self, step ):
return self.instance
def done( self, form_list, **kwargs ):
self.instance.save()
return HttpResponseRedirect(reverse(all-recipes))
.
#urls.py
------------------------------
url(r'^create-recipe/$', views.CreateRecipeWizard.as_view([RecipeForm, MeatFormSet, RecipeMeatNotesForm, RecipeStarchNotesForm]), name='create-recipe'),
.
I am a bit of a rookie with this django stuff. The Recipe part is much longer and more complicated but pretty much the same pattern. If any one could help point me in the right on how to get my ManyToManyField using through part figured out or pointed in the right direction it would be greatly appreciated.
To save the ManyToMany relationship on a formwizard process you can do something like this;
def done(self, form_list, **kwargs):
form_data_dict = self.get_all_cleaned_data()
m2mfield = form_data_dict.pop('m2mfield')
instance = form_list[0].save()
for something in m2mfield:
instance.m2mfield.add(something)
return render_to_response(
'done.html', {},
context_instance=RequestContext(self.request)
)
In this example the first form in the list is a ModelForm for the thing I'm trying to create and it has a ManyToManyField to another model for which I have a form second in the process. So I grab that first form & save it, then grab the field from the cleaned data from the second form and save the selected options to the M2M field.

django model forms filter queryset

I have the following model:
class Article(models.Model):
title = models.CharField()
description = models.TextField()
author = models.ForeignKey(User)
class Rating(models.Model):
value = models.IntegerField(choices=RATING_CHOICES)
additional_note = models.TextField(null=True, blank=True)
from_user = models.ForeignKey(User, related_name='from_user')
to_user = models.ForeignKey(User, related_name='to_user')
rated_article = models.ForeignKey(Article, null=True, blank=True)
dtobject = models.DateTimeField(auto_now_add=True)
Based upon the above model, i have created a model form, as follows:
Model Forms:
class RatingForm(ModelForm):
class Meta:
model = Rating
exclude = ('from_user', 'dtobject')
Excluding from_user because the request.user is the from_user.
The form renders well, but in to_user in the dropdown field, the author can rate himself as well. So i would want the current_user's name to populate in the dropdown field. How do i do it?
Override __init__ to remove current user from the to_user choices.
Update: More Explanation
ForeignKey uses ModelChoiceField whose choices are queryset. So in __init__ you have to remove the current user from to_user's queryset.
Update 2: Example
class RatingForm(ModelForm):
def __init__(self, current_user, *args, **kwargs):
super(RatingForm, self).__init__(*args, **kwargs)
self.fields['to_user'].queryset = self.fields['to_user'].queryset.exclude(id=current_user.id)
class Meta:
model = Rating
exclude = ('from_user', 'dtobject')
Now in the view where you create RatingForm object pass request.user as keyword argument current_user like this.
form = RatingForm(current_user=request.user)