Reputation: 111
I'm working on simple expenses manager. Every user is able to add/remove/edit an Operation, which represents expense or earning. However I have noticed a bug - while adding new Operation it is possible to choose other users Accounts and Categories.
Here is my Operation model:
class Operation(models.Model):
def get_category_color(self):
return Category.objects.get(name=self.category).color
types_tuples = ((-1, 'expense'), (1, 'earning'))
user = models.ForeignKey(User)
account = models.ForeignKey(Account)
category = models.ForeignKey(Category)
date = models.DateField()
amount = models.DecimalField(max_digits=10, decimal_places=2)
type = models.IntegerField(choices=types_tuples)
currency = models.CharField(max_length=3)
color = property(get_category_color)
OperationCreate view:
class OperationCreate(CreateView, OperationMixIn):
model = Operation
form_class = OperationForm
success_url = reverse_lazy('manage_operations')
def form_valid(self, form):
operation = form.save(commit=False)
operation.currency = Account.objects.get(pk=form.instance.account_id).currency
self.update_account_balance(form)
form.instance.user = self.request.user
return super(OperationCreate, self).form_valid(form)
and OperationForm:
class OperationForm(ModelForm):
class Meta:
model = Operation
fields = ['account', 'type', 'category', 'date', 'amount']
The question is how can I limit choices for Account and Category that are available during posting new Operation? I would like user to see only those which are related to his/her account.
I tried limit_choices_to
as a parameter for models.ForeignKey(Account)
and models.ForeignKey(Category)
in Operation model but couldn't make it work that way.
I assume I need to use a query which will return only Accounts and Categories related to the current user. However I have no clue how and where should I apply it.
Could you please point me in the right direction?
EDIT:
OperationForm edited due to @efkin suggestion:
class OperationForm(ModelForm):
class Meta:
model = Operation
fields = ['account', 'type', 'category', 'date', 'amount']
def __ini__(self, user, *args, **kwargs):
super(OperationForm, self).__init__(*args, **kwargs)
self.fields['account'] = ModelChoiceField(queryset=Account.objects.filter(user=user))
self.fields['category'] = ModelChoiceField(queryset=Category.objects.filter(user=user))
Upvotes: 0
Views: 150
Reputation: 111
Okay, so I did some more digging and came up with the solution. OperationForm
must be modified using ModelChoiceFiled (as @efkin said) and OperationCreate
should contains override for get_form_kwargs
method from ModelFormMixIn
:
class OperationCreate(CreateView, OperationMixIn):
model = Operation
form_class = OperationForm
success_url = reverse_lazy('manage_operations')
def get_form_kwargs(self):
kwargs = super(OperationCreate, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
def form_valid(self, form):
operation = form.save(commit=False)
operation.currency = Account.objects.get(pk=form.instance.account_id).currency
self.update_account_balance(form)
form.instance.user = self.request.user
return super(OperationCreate, self).form_valid(form)
Upvotes: 0
Reputation:
You could use a simple Form with ModelChoiceField fields for foreign keys.
Upvotes: 1