I'm trying to save some data through a form and I'm trying to use a
FormSet. The data to be saved is an invoice which contains a Product
and it's Details.
I was able to render everything in one place (this wasn't simple) and
to save the invoice and the detail to the DB. For some reason, the
Detail table is saving the Product ID but not the Invoice ID. This is
my models.py:
class Detail(models.Model):
invoice = models.ForeignKey(Invoice, null=True, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
subtotal = models.DecimalField(max_digits=9 , null=True, decimal_places=2)
class Invoice(models.Model):
date = models.DateField(default=datetime.date.today)
number = models.CharField(max_length=10, default='0000000000')
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
products = models.ManyToManyField(Product, null=True, blank=True)
total = models.DecimalField(max_digits=9 , null=True, decimal_places=2)
And this is my views.py:
def invoice_new(request):
DetailFormSet = formset_factory(DetailForm, extra=2)
if request.method == "POST":
invoice_form = InvoiceForm(request.POST)
detail_formset = DetailFormSet(request.POST)
if invoice_form.is_valid() and detail_formset.is_valid():
invoice = invoice_form.save(commit=False)
invoice.save()
for details in detail_formset:
details.save()
return redirect('invoice_detail', pk=invoice.pk)
else:
return redirect('invoice_error')
else:
invoice_form = InvoiceForm()
detail_formset=formset_factory(DetailForm, extra=2)
return render(request, 'invoice/invoice_edit.html', {'invoice_form': invoice_form, 'detail_form': detail_formset} )
I tried adding this to the body of the for loop:
details.invoice_id = invoice.pk
invoice.id prints OK, but it won't save the number to the DB. I don't see how it picks up product id just fine but not invoice's.
I'm adding forms.py
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoice
fields = ['date','number','supplier']
total = forms.DecimalField(disabled=True)
class DetailForm(forms.ModelForm):
class Meta:
model = Detail
fields = ['product','quantity']
You can set the invoice id before saving the form.
if invoice_form.is_valid() and detail_formset.is_valid():
invoice = invoice_form.save(commit=False)
invoice.save()
for details in detail_formset:
details.invoice = invoice # Set the invoice
details.save()
Related
I am working on a Django project and I want to query two different Models; Income and Expenditure using Date Range with Django Forms. I can query one Model at once but don't know how I can query both the Income and Expenditure table at the same time and as well count number of objects in both Models.
Below are my Models:
class Expenditure(models.Model):
description = models.CharField(max_length=100, null=False)
source = models.CharField(max_length=100, choices=CATEGORY_EXPENSES, null=True)
staff = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
amount = models.PositiveIntegerField(null=False)
Remarks = models.CharField(max_length=120, null=True)
date = models.DateField(auto_now_add=False, auto_now=False, null=False)
addedDate = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Expenses'
def __str__(self):
return self.description
class Income(models.Model):
description = models.CharField(max_length=100, null=False)
staff = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
amount = models.PositiveIntegerField(null=False)
remarks = models.CharField(max_length=120, null=True)
date = models.DateField(auto_now_add=False, auto_now=False, null=False)
addedDate = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Income Sources'
def __str__(self):
return self.description
My Django forms as in forms.py:
class IncomeSearchForm(forms.ModelForm):
start_date = forms.DateField(required=True, widget = IncomeDateField)
end_date = forms.DateField(required=True, widget = IncomeDateField)
class Meta:
model = Income
fields = ['start_date', 'end_date']
My views.py where I am able to use Date Range with Search form to query Income Model for Date Range Report.
def SearchIncomeRange(request):
#check for user session
if 'user' not in request.session:
return redirect('cashier-login')
else:
context = {}
searchForm = IncomeSearchForm(request.POST or None)
if searchForm:
listIncome = Income.objects.filter(date__range=[searchForm['start_date'].value(),searchForm['end_date'].value()])
else:
listIncome = Income.objects.all()
paginator = Paginator(listIncome, 5)
page = request.GET.get('page')
paged_listIncome = paginator.get_page(page)
#Calculate total amount of Date Range Result
total = listIncome.aggregate(total =
Sum('amount')).get('total') or 0
context.update({
'listIncome':paged_listIncome,
'searchForm':searchForm,
'total':total,
})
return render(request, 'cashier/search_income_range.html',context)
Someone should please help with the best way of filtering through my Income and Expenditure Models with their respective Totals and possibly count objects in both Models. Thanks.
thank you for reading, i have problem in Django Rest Framework project, i wrote only backend, and i must return url with user info from fields:
models.py
class Payment(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT) # we cannot delete user with money
# em
email = models.CharField(max_length=255, blank=False, null=True)
# m
shop_id = models.CharField(max_length=30, blank=False, null=True)
# oa
amount = models.DecimalField(default=0, max_digits=12, decimal_places=2)
class Curency(models.TextChoices):
UAH = 'UAH'
USD = 'USD'
EUR = 'EUR'
KZT = 'KZT'
RUB = 'RUB'
# currency
currency = models.CharField(
max_length=10,
choices=Curency.choices,
default=Curency.USD
)
# o
order_id = models.CharField(
max_length=255, null=True, blank=False, unique=False)
# s
sign = models.CharField(max_length=255, blank=False, null=True)
url = models.CharField(max_length=1000, null=True)
def __str__(self):
return f'Payment {self.user} of game {self.order_id}'
serializers.py
class PaymentSerializer(serializers.ModelSerializer):
# in order to work you should add related_name in Action model
class Meta:
model = Payment
fields = '__all__'
# balance is read only, because i don't want someone create account
# with money
read_only_fields = ('id', 'shop_id', 'sign', 'user', 'email')
views.py
class PaymentViewSet(viewsets.ModelViewSet,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated, )
serializer_class = PaymentSerializer
queryset = Payment.objects.all()
def get_queryset(self):
"""Return object for current authenticated user only"""
return self.queryset.all()
def perform_create(self, serializer):
serializer.save(user=self.request.user)
serializer.save(email=self.request.user.email)
shop_id = 'some id'
secret1 = "secret1"
amount = Payment.objects.get(amount) #there is problem
currency = Payment.objects.get(currency) #there is problem
order_id = Payment.objects.get(order_id) #there is problem
list_for_sign = map(
str, [shop_id, amount, secret1, currency, order_id])
result_string = ":".join(list_for_sign).encode()
sign_hash = hashlib.md5(result_string)
sign = sign_hash.hexdigest()
serializer.save(shop_id=shop_id)
serializer.save(sign=sign)
serializer.save(url="https://pay.freekassa.ru/?m={0}&oa={1}&o={2}&s={3}&em={4}¤cy={5}".format(
shop_id, amount, order_id, sign, self.request.user.email, currency))
return sign
i wanna put info when i post it in form, but have problem:
UnboundLocalError at /pay/payments/
local variable 'amount' referenced before assignment
i understand, that i take order, amount and currency before i give it, but what i should do?)
Update, form in DRF looks like:
DRF form looks like
You can simply access the form data like so:
amount = serializer.validated_data['amount']
or
amount = self.request.data["amount"]
Then you can do whatever you want with those variables, like to use it to search in the database
I am creating an invoice form.
I would like to have a function where if I change the inventory (dropdown search), the corresponding price will also change.
You can see an illustration of what I want here:
https://www.dropbox.com/s/4kpyfve3gzxmcls/dj006_ultimate_goal_for_adding_variable_attr.jpg?dl=0
What I know so far is I can I can query the inventory dropdown search through:
inventory = Inventory.objects.get(pk=request.POST['inventory_dropdown_id'])
price = inventory.price
But
how do I propogate such "get" function throughout all the forms (since I'm using query set)
how do I set the price (in the view.py) back to the html file when the html file is already rendered?
Is there away around this?
P.S. Probably been asked before here but I couldn't find any reference. (Hard to find what proper keyword to search) So if you want to post a link. I'd be happy to take a look at it.
================================================================
EDIT: Here is the model structure:
#MODELS.PY
class Invoice_Test_M2M(models.Model):
id = models.BigAutoField(primary_key=True)
ref_num = models.CharField(max_length=100)
def __str__(self):
return self.ref_num
class Inventory_Test_M2M(models.Model):
id = models.BigAutoField(primary_key=True)
inventory_name = models.CharField(blank=True, max_length=100)
invoice = models.ManyToManyField('Invoice_Test_M2M', through= "Invoice_Inventory_Through")
price = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
def __str__(self):
return self.inventory_name
class Invoice_Inventory_Through(models.Model):
invoice = models.ForeignKey(Invoice_Test_M2M, on_delete=models.CASCADE)
inventory = models.ForeignKey(Inventory_Test_M2M, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
quantity = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
amount = models.DecimalField(max_digits=9, decimal_places=2, blank=True, null=True)
#FORMS.PY
class Invoice_Inventory_ThroughForm(forms.ModelForm):
class Meta:
model = Invoice_Inventory_Through
exclude = ()
Inventory_TestLineItem_M2M_Formset = inlineformset_factory(Invoice_Test_M2M, Invoice_Inventory_Through, form=Invoice_Inventory_ThroughForm, fields = '__all__', exclude = [], can_delete = True)#
#VIEWS.PY
class Invoice_M2M_CreateView(CreateView):
model = Invoice_Test_M2M
success_url=reverse_lazy('music:album_list')
garbage = Invoice_Inventory_ThroughForm
garbage.price_val = 123
form = garbage
fields = '__all__'
def get_context_data(self, **kwargs):
context = super(Invoice_M2M_CreateView, self).get_context_data(**kwargs)
if self.request.POST:
context['track_formset'] = Inventory_TestLineItem_M2M_Formset(self.request.POST)
else:
context['track_formset'] = Inventory_TestLineItem_M2M_Formset()
context['price_val'] = 2
return context
def form_valid(self, form):
context = self.get_context_data(form=form)
formset = context['track_formset']
if formset.is_valid():
response = super().form_valid(form)
formset.instance = self.object
formset.save()
return response
else:
return super().form_invalid(form
This shall be done by Ajax and OnChange handler for the select. You create a view that you send it the id of product and it returns the price to ajax call and on the success of ajax you update the value of the price inputfield with the received price.
class Album(models.Model):
title = models.CharField(max_length=100, blank=True, default='')
price = models.FloatField()
upload_time = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('upload_time',)
class Status(models.Model):
user_id = models.IntegerField()
album_id = models.IntegerField()
favorite = models.BooleanField(default=False)
purchase = models.BooleanField(default=False)
history = models.BooleanField(default=False)
def __str__(self):
return self.user_id
in a ModelViewSet I wrote like this:
class index(viewsets.ModelViewSet):
serializer_class = AlbumSerializer
queryset = Album.objects.all()
As the image shown above, I need output the count of purchases of each Album, e.g. Album 1 has been purchased 4 times, Album 3 has been purchased 1 time.
But right now, my index view only generate the fields in Album data model.
What should I do to implement this, add the purchase number for each Album? Need your help...
You can add something like this to your serializer class to count it:
class AlbumSerializer(serializers.ModelSerializer):
purchase_count = serializers.SerializerMethodField(read_only=True)
def get_purchase_count(self, obj):
return Status.objects.filter(album_id=obj.id, purchase=True).count()
Connect your Album and User models as many to many relation:
class Status(models.Model):
user = models.ForeignKey('userapp.User', on_delete=models.CASCADE)
album = models.ForeignKey('albumapp.Album', on_delete=models.CASCADE)
favorite = models.BooleanField(default=False)
purchase = models.BooleanField(default=False)
history = models.BooleanField(default=False)
Don't forget to apply migrations.
Do query with annotation:
queryset = Album.objects.all().annotate(
purchase_count=Count('status', filter=Q(status__purchase=True)),
favorite_count=Count('status', filter=Q(status__favorite=True)),
history_count=Count('status', filter=Q(status__history=True)),
)
In attributes purchase_count, favorite_count and history_count you'll have corresponding values.
I created models called Interview, Users, Interview_interviewer like wise...
Interview_interviewer table has foreign keys from other models.
I just want to save data from both 2 tables to Interview_interviewer(Without django forms) table which is many to many table. So I just created the views and template for it. When button clicks it save the Interviewers to table along side with the interview. But when do it, It gave me and error called "User matching query does not exist".
/home/govinda/DMG/test3/myapp/views.py in hod_inter_interviewer_2
usr = User.objects.get(id=pid)
What should I do?
class Interview(models.Model):
Time = models.TimeField()
Date = models.DateField()
Venue = models.ForeignKey('Venue')
HOD = models.ForeignKey(User)
Vacancy = models.ForeignKey('Vacancy', on_delete=models.CASCADE)
Department = models.ForeignKey(Department, on_delete=models.CASCADE)
InterviewType = models.ForeignKey(InterviewType, on_delete=models.CASCADE)
Interviewer_Review = models.TextField(blank=True, null=True)
HOD_Review = models.TextField(blank=True, null=True)
HR_Review = models.TextField(blank=True, null=True)
NoOfPasses = models.PositiveIntegerField(blank=True, null=True)
NoOfFails = models.PositiveIntegerField(blank=True, null=True)
NoOfOnHolds = models.PositiveIntegerField(blank=True, null=True)
InterviewNo = models.IntegerField(blank=True, null=True)
Post = models.ForeignKey(Post, on_delete=models.CASCADE)
and
class Users(models.Model):
User = models.OneToOneField(User)
FullName = models.CharField(max_length=100)
Post = models.ForeignKey(Post)
UPhoto = models.FileField(upload_to=User_directory_path,null = True,blank=True)
Department = models.ForeignKey(Department)
UserRole = models.ForeignKey(UserRole)
def __str__(self):
return u'{}'.format(self.User)
and
class Interview_Interviewer(models.Model):
Interview = models.ForeignKey(Interview)
Interviewer = models.ForeignKey(User)
def __str__(self):
return u'{}'.format(self.Interviewer)
views are...
def hod_pre_interviwer_list(request, iid):
inter = Interview.objects.get(id=iid)
a = UserRole.objects.get(Role="Interviewer")
viewer = Users.objects.filter(UserRole=a.id)
return render(request, 'hod_inter_create_2.html', {'viewer': viewer, 'inter': inter, 'a':a})
def hod_inter_interviewer_2(request, iid, pid):
inter = Interview.objects.get(id=iid)
usr = User.objects.get(id=pid)
a = UserRole.objects.get(Role="Interviewer")
viewer = Users.objects.filter(UserRole=a.id)
usr_id = Users.objects.get(User=a.id)
inter_id = inter
person_id = usr_id
form = Interview_Interviewer(Interview=inter_id, Interviewer=person_id)
form.save()
return render(request, 'hod_inter_create_2.html', {'viewer': viewer, 'inter': inter})
urls are...
urlpatterns = [
url(r'^hod/hod_vacancy/test/part2/inter_list/(\d+)/$', hod_pre_interviwer_list, name="inter1"),
url(r'^hod/hod_vacancy/test/part2/inter_list/(\d+)/(\d+)/$', hod_inter_interviewer_2, name="inter2"),
]
template is...
<a type="submit" class="btn btn-primary" href="/hod/hod_vacancy/test/part2/inter_list/{{ inter.id }}/{{ viewer.id }}">Add</a>
Try using named groups in your url patterns
urlurl(r'^hod/hod_vacancy/test/part2/inter_list/?P<iid>[0-9]+)/?P<pid>[0-9]+/$', hod_inter_interviewer_2, name="inter2"),
If that doesn't work then i suggest trying User.object.get(pk=pid) as in most doc examples.
And make sure that there is a user with that id (iid) in the url.
You should also use get_object_or_404 for getting any single object from a model in the view as it gives a more user friendly and appropriate error.