Change Label Generic Inline Admin - django

I the following in the models.py:
class Item(models.Model):
date = models.DateField(_('date'), blank=True, null=True)
description = models.CharField(_('description'), max_length=255)
content_type = models.ForeignKey(ContentType, verbose_name=_('content type'))
object_id = models.PositiveIntegerField(_('object id'), db_index=True)
object = generic.GenericForeignKey('content_type', 'object_id')
class ItemAccountAmountRef(Item):
""" Items of which a Quote or an Invoice exists. """
amount = models.DecimalField(max_digits=10, decimal_places=2)
reference = models.CharField(max_length=200)
debit_account = models.ForeignKey(Account, related_name='receivables_receipt_debit_account')
credit_account = models.ForeignKey(Account, related_name='receivables_receipt_credit_account')
class PaymentItem(ItemAccountAmountRef):
pass
class Payment(models.Model):
invoice = models.ManyToManyField(Invoice, null=True, blank=True)
date = models.DateField('date')
attachments = generic.GenericRelation(Attachment)
site = models.ForeignKey(Site, related_name='payment_site', null=True, blank=True
items = generic.GenericRelation(PaymentItem)
in the admin.py:
class PaymentItemInline(generic.GenericTabularInline):
model = PaymentItem
form = PaymentItemForm
class PaymentAdmin(admin.ModelAdmin):
inlines = [PaymentItemInline]
in forms.py:
class PaymentItemForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PaymentItemForm, self).__init__(*args, **kwargs)
self.fields['credit_account'].label = "Bank Account"
In the PaymentItemInline the label is not changing. I have tried changing other attributes e.g. class which work. If I run through the init in debug mode I can see that the label variable is changing however when the form is rendered the field is still labelled credit account. Any suggestions?

You're 98% of the way there. Instead of trying to futz with the form field in __init__, just redefine it in your ModelForm. If you name it the same thing, django will be able to figure out that it is supposed to validate & save to the ForeignKey field. You can use the same formula to change a Field or Widget completely for a given field in a ModelForm.
You can find the default form field types for each model field type here: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#field-types
class PaymentItemForm(forms.ModelForm):
credit_account = forms.ModelChoiceField(label="Bank Account", queryset=Account.objects.all())
That's it. No need to override any functions at all : )
Incidentally, the docs for this field are here: https://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield

Related

How the through model object is created in django?

I want to overwrite a creation of M2M through model object. I thought that overwriting save method will be sufficient, but it appears that after saving admin form, the method is not called. I am having a hard time finding how this object is created.
Here is the code snippet
class ProductVariantToAttributeValue(models.Model):
product_variant = models.ForeignKey(ProductVariant, on_delete=models.CASCADE)
attribute_value = models.ForeignKey(AttributeValue, on_delete=models.CASCADE)
attribute = models.ForeignKey(
Attribute, on_delete=models.CASCADE, null=True, blank=True
)
class Meta:
db_table = "productvariants_to_attributevalues"
unique_together = [("product_variant", "attribute")]
verbose_name_plural = "Product Variants To Attribute Values"
def save(self, **kwargs):
self.attribute = self.attribute_value.attribute
super().save(**kwargs)

django checkbox select multiple models

Hi I have the following django model:
class Issue(models.Model):
title = models.CharField(max_length=200)
date = models.DateTimeField(auto_now=True)
assignee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='assignee')
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owner', null=True, blank=True)
description = models.TextField()
state = models.IntegerField(choices=STATUS_CHOICES, default=1)
priority = models.IntegerField(choices=RELEVANCE_CHOICES, default=2)
expired_date = models.DateField(auto_now=False, null=True, blank=True)
and a form which allow a user to create an Issue instance:
class IssueForm(forms.ModelForm):
class Meta:
model = Issue
fields = ('title', 'description', 'assignee', 'state', 'priority', 'expired_date')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['title'].label = "Titolo"
self.fields['description'].label = "Descrizione"
self.fields['state'].label = "Stato"
self.fields['priority'].label = "Priorità"
self.fields['expired_date'].label = "Termine"
self.fields['expired_date'].widget.attrs.update({'class': 'datepicker'})
self.fields['assignee'] = forms.MultipleChoiceField(
choices=self.fields['assignee'].choices,
widget=forms.CheckboxSelectMultiple,
label=("Assegnatario")
)
def clean(self):
cleaned_data = super().clean()
user_id = [i for i in cleaned_data['assignee']]
cleaned_data['assignee'] = [User.objects.get(id=i) for i in user_id]
return cleaned_data
I render this form and the field assignee is a checkbox.
I would like to be able to choose several assignee for the same issue, but I got an error because the Issue model expect just one User instance
How can I modify my model Issue in order to get more than one user ?
Thanks
you can create a new class and name it Issue_Instance where every Issue Object can have an assignee as a foreign key the problem that the relation is one to many because you have to choose more than one assignee and Django doesn't support the idea of having Array or List of Foreign Keys(I don't know any frame works that do :=) ) so I would suggest creating a new class or make the foreign key relation one-to-many key field read about it it will be very useful to solve your problem

Need to get id instead of selected value in modelchoicefield django

This is a very very basic question and i have already searched and tried lots of ways to do it but i want to know the good practice/best method to go about it.
There is a table in which i am trying to store the user selected code from another table. What is want is
A model form combo box which shows description field value while saves its respective pos_code in the table.
This is my model and forms:
pos_code = forms.ModelChoiceField(queryset=Positions.objects)
Here i want to insert the pos_code against the user selected description:
class TmpPlInvoice(models.Model):
voucher_id = models.CharField(primary_key=True, max_length=10)
pos_code = models.ForeignKey(Positions, models.DO_NOTHING, db_column='pos_code', blank=True, null=True)
class Meta:
managed = False
db_table = 'tmp_pl_invoice'
I'm getting the choice field from this model:
class Positions(models.Model):
pos_code = models.CharField(primary_key=True, max_length=10, blank=True, null=True)
description = models.CharField(max_length=100, blank=True, null=True)
class Meta:
managed = False
db_table = 'positions'
def __unicode__(self):
return self.description
But it gives me description instead of pos_code. I know that I am returning description but I need to show it to user and get code in the views.
Here is my full form
class TmpForm(forms.ModelForm):
description = forms.ModelChoiceField(queryset=Positions.objects.all())
class Meta:
model = TmpPlInvoice
exclude = ['net_amt', 'post_date', 'address', 'posted', 'voucher_date', 'particulars']
What i have
[IMG]http://i68.tinypic.com/zj89yx.jpg[/IMG]
Current form output
{'voucher_id': u'3452345', 'description': Positions: Premier Industrial Chemicals}
I can't use this 'description'. I need to save the code of Premier Industrial Chemicals in my TmpForm
What i need
[IMG]http://i66.tinypic.com/nh0x2a.jpg[/IMG]
Desired form output
{'voucher_id': u'3452345', 'pos_code': 0001}
This model form saved my life. The MyModelChoiceField class shows the label but send id on the backend.
class MyModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.description
class TmpFormm(forms.ModelForm):
pos_code = MyModelChoiceField(queryset=Positions.objects.all(), widget=forms.Select(attrs={'class': 'select2_single form-control', 'blank': 'True'}))

Limit values in the modelformset field

I've been trying to solve this problem for a couple of days now, getting quite desperate. See the commented out code snippets for some of the things I've tried but didn't work.
Problem: How can I limit the values in the category field of the IngredientForm to only those belonging to the currently logged in user?
views.py
#login_required
def apphome(request):
IngrFormSet = modelformset_factory(Ingredient, extra=1, fields=('name', 'category'))
# Attempt #1 (not working; error: 'IngredientFormFormSet' object has no attribute 'fields')
# ingrformset = IngrFormSet(prefix='ingr', queryset=Ingredient.objects.none())
# ingrformset.fields['category'].queryset = Category.objects.filter(user=request.user)
# Attempt #2 (doesn't work)
# ingrformset = IngrFormSet(prefix='ingr', queryset=Ingredient.objects.filter(category__user_id = request.user.id))
models.py:
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, null=True, blank=True)
class Ingredient(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, null=True, blank=True)
category = models.ForeignKey(Category, null=True, blank=True)
counter = models.IntegerField(default=0)
forms.py:
class IngredientForm(ModelForm):
class Meta:
model = Ingredient
fields = ('name', 'category')
UPDATE: I've made some progress but the solution is currently hard-coded and not really usable:
I found out I can control the categoryform field via form class and then pass the form in the view like this:
#forms.py
class IngredientForm(ModelForm):
category = forms.ModelChoiceField(queryset = Category.objects.filter(user_id = 1))
class Meta:
model = Ingredient
fields = ('name', 'category')
#views.py
IngrFormSet = modelformset_factory(Ingredient, form = IngredientForm, extra=1, fields=('name', 'category'))
The above produces the result I need but obviously the user is hardcoded. I need it to be dynamic (i.e. current user). I tried some solutions for accessing the request.user in forms.py but those didn't work.
Any ideas how to move forward?
You don't need any kind of custom forms. You can change the queryset of category field as:
IngrFormSet = modelformset_factory(Ingredient, extra=1, fields=('name', 'category'))
IngrFormSet.form.base_fields['category'].queryset = Category.objects.filter(user__id=request.user.id)
Category.objects.filter(user=request.user)
returns a list object for the initial value in your form which makes little sense.
Try instead
Category.objects.get(user=request.user)
or
Category.objects.filter(user=request.user)[0]

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)