I'm using Django admin.TabularInline class inorder to add multiple objects in a Foreinkey relationship as below:
admin.py:
class HeadFlowDatasetInline(admin.TabularInline):
model = HeadFlowDataset
extra = 0
class ProductAdmin(admin.ModelAdmin):
list_display = (
...
)
search_fields = (
...
)
fields = (
...
)
inlines = [HeadFlowDatasetInline]
def save_model(self, request, obj, form, change):
obj.created_by = request.user
obj.last_updated_by = request.user
obj.save()
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
instance.user = request.user
instance.save()
Also these are my models for Product and HeadFlowDataset:
class Product(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
)
main_model = models.ForeignKey(
MainModel,
on_delete=models.SET_NULL,
null=True,
verbose_name="نام مدل اصلی پمپ",
)
usage = models.ManyToManyField(Usage)
sub_usage = models.ManyToManyField(SubUsage)
pump_type = models.ForeignKey(
PumpType,
on_delete=models.SET_NULL,
null=True,
verbose_name="تیپ پمپ",
)
pump_name = models.CharField(
max_length=255,
null=False,
blank=False,
verbose_name="نام محصول",
unique=True,
)
... # other fields not related to this question.
def __str__(self):
return self.pump_name
class HeadFlowDataset(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
)
product = models.ForeignKey(
Product,
on_delete=models.CASCADE,
)
head = models.FloatField()
flow = models.FloatField()
def __str__(self):
return self.product.pump_name
And for this purpose, this approach is working just fine. But the problem occurs when I'm trying to remove a HeadFlowDataset object from the add product object page. As shown in the picture below, there is a checkbox item in front of each HeadFlowDataset object, but checking it and saving does not work. I could not find any other way to make this work neither. Can anyone show me a way to do this?
because you set the commit to False then the operations don't run by default like delete and save you can use your formset.deleted_objects to iterate and delete them if have a delete permission
Related
I am getting Issue while edit a record based on CHatquestion ID, if option is null then i need to add a record based on same chatquestion id, if chatqustion id exist in option it will work,
i am trying to multiple way to solve this issue but still can't find solution.
Models.py # thease are all 3 models
class Problem(models.Model):
Language = models.IntegerField(choices=Language_CHOICE, default=1)
type = models.CharField(max_length=500, null=True, blank=True)
def __str__(self):
return self.type
class ChatQuestion(models.Model): # Eding record based on chatquestion id
question = RichTextField(null=True, blank=True)
problem_id = models.ForeignKey(
Problem,
models.CASCADE,
verbose_name='Problem',
)
def __str__(self):
return self.question
is_first_question = models.BooleanField(default=False)
class Option(models.Model):
option_type = models.CharField(max_length=250, null=True, blank=True)
question_id = models.ForeignKey(
ChatQuestion,
models.CASCADE,
verbose_name='Question',
null=True,
blank=True
)
problem=models.ForeignKey(
Problem,
models.CASCADE,
verbose_name='Problem',
null=True,
blank=True
)
next_question_id = models.ForeignKey(ChatQuestion, on_delete=models.CASCADE, null=True, blank=True,
related_name='next_question')
def __str__(self):
return self.option_type
forms.py
class EditQuestionForm(forms.ModelForm):
class Meta:
model = ChatQuestion
fields =('question','problem_id')
class EditOptionForm(forms.ModelForm):
class Meta:
model = Option
fields =('option_type',)
views.py
def question_edit(request,id=None):
if id is not None:
queryset = get_object_or_404(ChatQuestion,pk=id)
queryset1=get_object_or_404(Option,question_id=queryset )
else:
queryset = None
queryset1 = None
if request.method=="POST":
form = EditQuestionForm(request.POST ,instance=queryset)
form1=EditOptionForm(request.POST, instance=queryset1)
if form.is_valid() and form1.is_valid():
question=form.cleaned_data['question']
option_type=form1.cleaned_data['option_type']
if id:
queryset.question=question
queryset.save()
queryset1.option_type=option_type
queryset1.save()
messages.success(request,'Sucessful')
return redirect('/fleet/list_chatbot')
else:
print(form.errors)
messages.error(request,'Please correct following',form.errors)
elif id:
form = EditQuestionForm(instance=queryset)
form1=EditOptionForm(instance=queryset1)
if not queryset1:
form1=EditOptionForm()
else:
form = EditQuestionForm()
form1=EditOptionForm()
context={
'form':form,
'form1':form1
}
return render(request,'chatbot/question_edit.html',context=context)
I have two models which are each in a different app. Stock model references Financials model through a foreignkey relationship as shown below. with the current Stock Viewset, also displayed below, I am able to access the individual stock through localhost:8000/stocks/aapl, but I would like to extend that url to include the financials foreign key data such as localhost:8000/stocks/aapl/financials/balance-sheet/. I was told to use Extra Actions, which I've attmpted and posted below but no luck.
Any clue how to do this ?
class Stock(models.Model):
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
ticker = models.CharField(max_length=10, unique=True, primary_key=True)
slug = models.SlugField(default="", editable=False)
financials = models.OneToOneField(
Financials, on_delete=models.CASCADE, default=None
)
def get_financials(self):
return self.financials
financial model
class Financials(models.Model):
# ticker = models.ForeignKey(
# Stock, on_delete=models.CASCADE, related_name="balance_sheets"
# )
balance_sheet = models.ForeignKey(
BalanceSheet, on_delete=models.CASCADE, related_name="balance_sheets"
)
income_statement = models.ForeignKey(
IncomeStatement, on_delete=models.CASCADE, related_name="income_statements"
)
cashflows_statement = models.ForeignKey(
CashflowsStatement,
on_delete=models.CASCADE,
related_name="cashflows_statements",
default=None,
)
stocks.views.py
class StockViewSet(viewsets.ModelViewSet):
queryset = Stock.objects.all()
serializer_class = StockSerializer
lookup_url_kwarg = "ticker"
lookup_field = "ticker__iexact"
#action(detail=True, methods=['post', 'get'])
def financials(self, request, ticker=None):
stock = self.get_object()
financials = stock.get_financials()
return Response({financials})
I've method in admin.py
def save_model(self, request, instance, form, change):
user = request.user
instance = form.save(commit=False)
if not change or not instance.created_by:
instance.created_by = user
instance.save()
form.save_m2m()
if instance.send_to_killer:
serializer = OrderSerializer(
instance)
emailClass = Email()
emailClass.sendemail(serializer, 1, instance)
return instance
and other one is
class Email(object):
def sendemail(self, data, sendfrom, instance):
print(instance.id)
orders_item = order_item.objects.filter(order_id=instance.id)
print(orders_item)
for item in orders_item:
print(item.qty)
I received instance.id but not getting orders_item as items are saved after order. so how i can get order items data while saving m2m ??
models are
class Order(models.Model):
date = models.DateField(default=timezone.now)
project = models.ForeignKey(
Project, on_delete=models.CASCADE, limit_choices_to={'is_active': True})
send_to_killer = models.BooleanField(default=False)
send_to_sigler = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
class order_item(models.Model):
# When a Event is deleted, upload models are also deleted
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="order_item",
related_query_name="order_item")
item = models.ForeignKey(
Item, on_delete=models.CASCADE, limit_choices_to={'is_active': True}, blank=True, default="")
qty = models.IntegerField(default=0, blank=True)
price = models.DecimalField(
default=Decimal(0), max_digits=12, decimal_places=2, blank=True)
and serializers of order and order_itemare
class orderItemSerializer(serializers.ModelSerializer):
class Meta:
model = order_item
fields = ['qty', 'price']
class OrderSerializer(serializers.ModelSerializer):
order_items = orderItemSerializer(many=True, read_only=True)
class Meta:
model = Order
fields = ['id', 'date', 'project', 'order_items']
You can do it using a signal.
from django.db.models.signals import m2m_changed
m2m_changed.connect(sendemail, sender=YourTable.YourTable_many_to_many_attribute.through)
For detail, please share your model
I have followed spapas tutorial on CBV's and tried to apply a mixin on a create view. But looks like it doesn't evaluate correctly the if not form.invoice.requester for a user foreign key because it always says: RelatedObjectDoesNotExist and it points to the field evaluated in the if not line.
What can be wrong?
views.py
class AuditableMixin(object, ):
def form_valid(self, form, ):
if not form.instance.requester:
form.instance.requester = self.request.user
form.instance.modified_by = self.request.user
return super().form_valid(form)
class NewOrderView(LoginRequiredMixin, PermissionRequiredMixin, AuditableMixin, generic.CreateView):
permission_required = 'orders.add_order'
form_class = NewOrderForm
model = Order
title = 'New Order'
extra_context = {'title': title}
forms.py
class NewOrderForm(forms.ModelForm):
class Meta:
model = Order
widgets = {
'order_details': forms.Textarea,
}
exclude = (
'status',
'invoice',
'requester',
'modified_by',
)
models.py
class Order(models.Model):
STATUS_CHOICES = (
('open', 'Open'),
('inprogress', 'In Progress'),
('rejected', 'Rejected'),
('closed','Closed'),
('resolved','Resolved'),
)
subject = models.CharField(
max_length=30,
)
requester = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name='orders',
)
order_details = models.TextField(
)
created = models.DateTimeField(
auto_now_add=True,
)
updated = models.DateTimeField(
auto_now=True,
)
status = models.CharField(
max_length=12,
default='open',
choices= STATUS_CHOICES,
)
invoice = models.ForeignKey(
Invoice,
on_delete=models.PROTECT,
blank= True,
null=True,
related_name='orders',
)
modified_by = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name='orders_modified',
)
def __str__(self):
return self.subject
def get_absolute_url(self):
return reverse('Order_Detail', args=[str(self.pk)])
class Meta:
ordering = ['-created']
Thank you.
When calling the ForeignKey object on a model, you're actually telling Django to perform the query to fetch the related object. To check if the relationship exists, you should check <fieldname>_id which is the actual name of the field:
if not form.instance.requester_id:
form.instance.requester = self.request.user
That way if requester_id is None you don't perform the query, which would through the RelatedObjectDoesNotExist error.
Im trying to find a method for posting a string value and saving it to a foreign key field instead of using the pk.
My models:
class CustomUser(models.Model):
username = models.CharField(max_length=500, unique=True)
def __str__(self):
return self.username
class Order(models.Model):
ordernumber = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False)
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, blank=True)
amount = models.FloatField(null=True, blank=True)
def __str__(self):
return "{0}".format(self.ordernumber)
And my serializer:
class OrderSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = Order
fields = ('id','username', 'ordernumber', 'amount')
read_only_fields = ('id')
When using GET, everything works perfectly, but I can't seem to fix the POST method.
I tried to override the create method like this:
def create(self, validated_data):
username = validated_data.pop('username')
order = Order.objects.create(**validated_data)
order.user = CustomUser.objects.get(username=username)
order.save()
return order
But I get a KeyError on the username = validated_data.pop('username') line: Exception Value:'username'
When you use source with nested fields, data will be accessible as validated_data['parent_field']['child_field']. Try this:
def create(self, validated_data):
user_data = validated_data.pop('user')
username = user_data.pop('username')
order = Order.objects.create(**validated_data)
order.user = CustomUser.objects.get(username=username)
order.save()
return order