how to access field models which on admin.TabularInline - python

I'm new on django, and I want to build an application called "Recycle Bank".
Here's my models.py
class Waste(models.Model):
name = models.CharField(max_length=20)
wtype = models.ForeignKey(WasteType)
specification = models.TextField(blank=True)
purchasing_price = models.DecimalField(max_digits=8, decimal_places=2)
selling_price = models.DecimalField(max_digits=8, decimal_places=2)
class Purchasing(models.Model):
timestamp = models.DateTimeField(auto_now=True)
client = models.ForeignKey(Client)
officer = models.ForeignKey(Officer)
waste = models.ManyToManyField(Waste, through='PurchasingDetail')
def __str__(self):
return self.client.user.username
class PurchasingDetail(models.Model):
waste = models.ForeignKey(Waste)
purchasing = models.ForeignKey(Purchasing)
weight = models.DecimalField(max_digits=8, decimal_places=2)
price = models.DecimalField(max_digits=8, decimal_places=2)
Here's my admin.py
class PurchasingDetailInlineAdmin(admin.TabularInline):
model = PurchasingDetail
extra = 1
class PurchasingAdmin(admin.ModelAdmin):
list_display = ['client', 'timestamp', 'officer',]
fields = ('client',)
inlines = [PurchasingDetailInlineAdmin,]
def save_model(self, request, obj, form, change):
obj.officer_id = request.user.id
obj.save()
So, I want to set the price object in PurchasingDetail(models.Model) with specified counting (in this case: Waste.purchasing_price * PurchasingDetail.weight). I know I have to get access to PurchasingDetail(models.Model) object like I do on my save_model(). How to do this?
Here's my admin interface screenshots https://drive.google.com/open?id=0B2dFcp9QmLL2X2duVHVfeVNHNlU
Thank you.

Related

Auto list fields from many-to-many model

I've created a model of analysis types and then I created a table that groups several analyses into one group:
class AnalysisType(models.Model):
a_name = models.CharField(max_length=16,primary_key=True)
a_measur = models.CharField(max_length=16)
a_ref_min = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
a_ref_max = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
# analysis_group = models.ForeignKey(AnalysysGroup, on_delete=models.CASCADE, default=1)
def __str__(self):
return f"{self.a_name} - {self.a_measur}"
class AnalysysGroup(models.Model):
group_name = models.CharField(max_length=32)
analysis = models.ManyToManyField(AnalysisType, blank=True)
def __str__(self):
return f"{self.group_name}"
I want to have the option to multiply add values via the admin panel (I.E. I chose Analysis type then below appear fields to fill)
class PatientGroupAnalysis(models.Model):
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
analysis_date = models.DateTimeField()
analysis_type = models.ForeignKey(AnalysysGroup, on_delete=models.CASCADE, default=1)
# amalysis_data = ???
def __str__(self):
return f"{self.patient}: {self.analysis_date} - {self.analysis_type} - {self.analysis_data}"
I tried to use analysis_data = analysis.type.objects.all() and etc. but that's the wrong way.
Try this:
Admin panel with StackedInline
from django.contrib import admin
from .models import AnalysisType, PatientGroupAnalysis
# Register your models here.
class PatientGroupAnalysisInline(admin.StackedInline):
model = PatientGroupAnalysis
#admin.register(AnalysisType)
class AnalysisTypeAdmin(admin.ModelAdmin):
list_display = ["id", "a_name", "a_measur", "a_ref_min", "a_ref_max"]
search_fields = ("id", "a_name")
inlines = [PatientGroupAnalysisInline]

Django generic create view . Can we add conditions to save data from the form?

This is what my code looks like and I want to add some condition to the Borrower create view like if the stock method of book returns 0 then don't list that book in field while creating a new borrower or if it isn't possible at least throw some error while adding borrower to that book.
models.py:
class Book(models.Model):
id = models.UUIDField(primary_key=True, unique=True,
default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
summary = models.TextField(
max_length=1000, help_text="Enter a brief description of the book")
isbn = models.CharField('ISBN', max_length=13,
help_text='13 Character https://www.isbn-international.org/content/what-isbn')
genre = models.ManyToManyField(
Genre, help_text="Select a genre for this book")
language = models.ForeignKey(
'Language', on_delete=models.SET_NULL, null=True)
total_copies = models.IntegerField()
pic = models.ImageField(blank=True, null=True, upload_to='books')
def stock(self):
total_copies = self.total_copies
available_copies = total_copies - \
Borrower.objects.filter(book=self).count()
if available_copies > 0:
return available_copies
else:
return 0
def __str__(self):
return self.title
class Borrower(models.Model):
id = models.UUIDField(primary_key=True, unique=True,
default=uuid.uuid4, editable=False)
student = models.ForeignKey('Account', on_delete=models.CASCADE)
book = models.ForeignKey('Book', on_delete=models.CASCADE)
issue_date = models.DateField(
null=True, blank=True, help_text='YYYY-MM-DD', default=date.today)
return_date = models.DateField(
null=True, blank=True, help_text='YYYY-MM-DD')
def __str__(self):
return self.student.name.title()+" borrowed "+self.book.title.title()
def fine(self):
today = date.today()
fine = 0
if self.return_date <= today:
fine += 5 * (today - self.return_date).days
return fine
views.py:
class BorrowerView(LoginRequiredMixin, ListView):
model=Borrower
context_object_name='borrowers'
template_name = 'library/borrower_list.html'
def get_context_data(self, **kwargs):
context=super().get_context_data(**kwargs)
if self.request.user.is_admin or self.request.user.is_superuser:
context['borrowers']=context['borrowers']
else:
context['borrowers']=context['borrowers'].filter(student = self.request.user.id)
return context
class BorrowerCreate(LoginRequiredMixin, UserAccessMixin, CreateView):
model=Borrower
permission_required= 'borrowers.add_borrowers'
fields='__all__'
success_url=reverse_lazy('library:borrower-list')
def form_valid(self, form):
form.instance.user=self.request.user
return super(BorrowerCreate, self).form_valid(form)
class BorrowerDetail(LoginRequiredMixin, DetailView):
model=Borrower()
context_object_name='borrower'
template_name='library/borrower.html'
class Book(models.Model):
id = models.UUIDField(primary_key=True, unique=True,
default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=100)
summary = models.TextField(
max_length=1000, help_text="Enter a brief description of the book")
isbn = models.CharField('ISBN', max_length=13,
help_text='13 Character https://www.isbn-international.org/content/what-isbn')
genre = models.ManyToManyField(
Genre, help_text="Select a genre for this book")
language = models.ForeignKey(
'Language', on_delete=models.SET_NULL, null=True)
total_copies = models.IntegerField()
pic = models.ImageField(blank=True, null=True, upload_to='books')
#new, use this to keep track of available books
available_copies = models.IntegerField()
def __str__(self):
return self.title
When any borrower borrows a copy of the book, you will subtract it from the total copies.
class BorrowerCreate(LoginRequiredMixin, UserAccessMixin, CreateView):
model=Borrower
permission_required= 'borrowers.add_borrowers'
fields='__all__'
success_url=reverse_lazy('library:borrower-list')
#remember to get the object using slug or 404
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
book = Book.objects.get(id=instance.book.id)
#get the book id from the form and check if the book is still available, then subtract.
if book.available_copies > 0:
book.available_copies -= 1
book.save()
instance.save()
message.success(self.request, _("successful")
message.error(self.request, _("Book not in stock")
return super(BorrowerCreate, self).form_valid(form)
If user return the book and click returned. you can perform a similar action by adding to available copies.
This is not the solution, you can write a fat model with methods that takes care of both borrowing and return. Like this
def borrow(self):
self.available_copies -= 1
def returned(self):
self.available_copies += 1
You can call these two methods in different views or define a signal that call them using pre_save
Ist:
Instead of defining a new method which you called stock, why not add stock as a field instead of making a database query.
2nd:
calling the class inside the same class is not the best way to make queries inside the class.
3rd:
To add a condition while adding an object, you need to override the save method of the object like this.
def save(self, *args, **kwargs):
# do_something() here.....
# then
return super().save(*args, **kwargs)
The above code will enable you to perform any action before saving the object.
Another way you can do this is inside the form_valid function like this.
def form_valid(self, form):
instance = form.save(commit=False)
# commit = False will make sure that the form is not saved
# then you can now query the database and check conditions like
if Borrower.object.all().count() > 0:
instance.save()
messages.success(self.request, _("saved successfully")
else:
messages.error(self.request, _("Error")
return redirect("URL")

Django Rest Framework: How to get instance of related foreign key

Note: IF INFORMATION BELOW IS NOT CLEAR TO UNDERSTAND - PLEASE ASK ME, I WILL UPDATE AND POST INFORMATION YOU NEED | It is important for me
In Warehouse(models.Model) I have amount attribute and
in ChosenProduct(models.Model) - quantity
I'm trying to get amount in Warehouse through chosen_products instance in App_formSerializer to add the quantity of chosen_product
But I can not get the chosen_products objects from instance
--> below Out:
class WarehouseSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(
source='category_product.category_name')
posted_user = serializers.ReadOnlyField(
source='posted_user.username')
class Meta:
model = Warehouse
fields = ['id', 'category_product', 'category_name', 'condition',
'product_name', 'amount', 'barcode', 'f_price', 'created_at', 'updated_at', 'posted_user']
class ChosenProductSerializer(serializers.ModelSerializer):
product_info = WarehouseSerializer(source='product', read_only=True)
period_info = Product_periodSerializer(source='period', read_only=True)
class Meta:
model = ChosenProduct
exclude = ('app_form',)
class App_formSerializer(serializers.ModelSerializer):
chosen_products = ChosenProductSerializer(many=True)
def update(self, instance, validated_data):
instance.terminated = validated_data.get('terminated', instance.terminated)
if instance.terminated == True :
print('-----------TRUE--------------------')
print(instance.chosen_products)
print('-----------PRINT--------------------')
instance.save()
return instance
class Meta:
model = App_form
fields = '__all__'
Out
-----------TRUE--------------------
creditapi.ChosenProduct.None
-----------PRINT--------------------
QUESTION UPDATED
models.py
class Warehouse(models.Model):
category_product = models.ForeignKey(
Category_product, on_delete=models.CASCADE)
product_name = models.CharField(max_length=200, unique=True)
condition = models.BooleanField(default=False)
amount = models.IntegerField()
barcode = models.BigIntegerField()
f_price = models.CharField(max_length=255, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
posted_user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
def __str__(self):
return self.product_name
class App_form(models.Model):
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,12}$', message="Phone number must be entered in the format: '998981234567'. Up to 12 digits allowed.")
terminated = models.BooleanField(default=False)
name = models.CharField(max_length=150)
phone_number = models.CharField(validators=[phone_regex], max_length=13)
def __str__(self):
return self.surname
class ChosenProduct(models.Model):
product = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
quantity = models.IntegerField()
app_form = models.ForeignKey(App_form, on_delete=models.CASCADE, related_name='chosen_products')
def __str__(self):
return self.product.product_name
If you write instance.chose_products you access the manager, not the QuerySet that contains the items. You can use .all() to obtain the QuerySet with all the objects:
print(instance.chosen_products.all())
If you access a ForeignKey in reverse, you have a manager, since zero, one, or more elements can refer to the instance.
You can for example aggregate over the chose_products, for example if you want to retrieve the number of related chose_products, you can use:
print(instance.chosen_products.count())
I would however advise not store (aggregated) data in the App_form, but aggregate data when you need it. Data duplication is an anti-pattern, and it turns out it is hard to keep data in sync.

i am building a django projects using a medium blogpost, i cannot understand the purpose of these three lines of code

this application is a order manager and I am new to django therefore
i do not know what these line of code do so please help me understand what this piece of code is used for
objects = models.Manager()
browser = ProductManager()
tag_final_value.short_description = 'Value'
this my models.py file
class Product(models.Model):
title = models.CharField(max_length=150, unique=True)
category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)
active = models.BooleanField(default=True)
value = models.DecimalField(default=0.00, decimal_places=2, max_digits=10)
discount_value = models.DecimalField(default=0.00, decimal_places=2, max_digits=10)
final_value = models.DecimalField(default=0.00, decimal_places=2, max_digits=10)
qty = models.PositiveIntegerField(default=0)
objects = models.Manager()
browser = ProductManager()
class Meta:
verbose_name_plural = 'Products'
def save(self, *args, **kwargs):
self.final_value = self.discount_value if self.discount_value > 0 else self.value
super().save(*args, **kwargs)
def __str__(self):
return self.title
def tag_final_value(self):
return f'{CURRENCY} {self.final_value}'
tag_final_value.short_description = 'Value'
this my managers.py file
from django.db import models
class ProductManager(models.Manager):
def active(self):
return self.filter(active=True)
def have_qty(self):
return self.active().filter(qty__gte=1)
objects is your default manager
You can get all objects on particular model by using
products = Products.objects.all()
browser is your custom model you have created by using a class ProductManager.
You can get all objects using this manager by using
products = Products.browser.all()
Basically, by defining a custom manager you can narrow down your queryset with some methods you would like to add. So, that you don't have to user filters and other complex queryset all the time you can just call your custom manager
You can read more here.

Django rest framework bind decimal values from Brazilian currency format

I have to serialize data for a django rest framework application, some of values will be on Brazilian currency format like 1.234,45.
How can I bind those number to work with django rest serializer and django models
My model:
class Produto(models.Model):
prod_codigo = models.AutoField(db_column='prod_codigo', primary_key=True)
prod_alias = models.CharField(db_column='prod_alias', max_length=50, null=False)
prod_descricao = models.CharField(db_column='prod_descricao', max_length=255, null=False)
prod_valor_venda = models.DecimalField(db_column='prod_valor_venda', max_digits=13, decimal_places=2)
prod_valor_compra = models.DecimalField(db_column='prod_valor_compra', max_digits=13, decimal_places=2)
prod_peso_b = models.DecimalField(db_column='prod_peso_b', max_digits=13, decimal_places=2)
prod_peso_l = models.DecimalField(db_column='prod_peso_l', max_digits=13, decimal_places=2)
My serializer:
class ProdutoSerializer(serializers.Serializer):
prod_codigo = serializers.IntegerField(read_only=True)
prod_alias = serializers.CharField(required=False, allow_blank=True)
prod_descricao = serializers.CharField(required=True, allow_blank=True)
prod_valor_venda = serializers.DecimalField(max_digits=13, decimal_places=2)
prod_valor_compra = serializers.DecimalField(max_digits=13, decimal_places=2)
prod_peso_b = serializers.DecimalField(max_digits=13, decimal_places=2)
prod_peso_l = serializers.DecimalField(max_digits=13, decimal_places=2)
class Meta:
model = Produto
def create(self, validated_data):
return Produto.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.prod_codigo = validated_data.get('prod_codigo', instance.prod_codigo)
instance.prod_alias = validated_data.get('prod_alias', instance.prod_alias)
instance.prod_descricao = validated_data.get('prod_descricao', instance.prod_descricao)
instance.prod_valor_venda = validated_data.get('prod_valor_venda', instance.prod_valor_venda)
instance.prod_valor_compra = validated_data.get('prod_valor_compra', instance.prod_valor_compra)
instance.prod_peso_b = validated_data.get('prod_peso_b', instance.prod_peso_b)
instance.prod_peso_l = validated_data.get('prod_peso_l', instance.prod_peso_l)
instance.prod_peso_q = validated_data.get('prod_peso_q', instance.prod_peso_q)
instance.save()
return instance
If I understand it correctly and 1.234,45 equals to 1.23445 why not handle this on the client side? In my opinion this is the best way to handle to handle format issues.
If you still wanna do it in your backend app you can override to_representation(self, instance)
or use SerializerMethodField like the code below:
class ProdutuSerializer(serializer.ModelSerializer):
...
your_field = serializers.SerializerMethodField()
def get_your_field_name(self, instance):
""" stringify your field """
return "some format" % instance.field
Hope that it helps!

Categories