Doesn't save data django Foreignkey model - python

I've two model. I would like to save data from ForeignKey model. I'm created a modelform and save with my main foreignkey model. But I got this error ValueError at /c/customer/1/
Cannot assign "'1'": "BillingData.customer" must be a "CustomerData" instance.
I created Django model form and hocked up with view.
models.py file
class CustomerData(models.Model):
customer_name = models.CharField(max_length=100)
customer_no = models.CharField(max_length=100, default='', blank=True)
mobile_number = models.IntegerField()
alternative_phone = models.IntegerField(null=True, blank=True)
union_name = models.ForeignKey(UnionName, on_delete=models.SET_NULL, null=True)
word_name = models.ForeignKey(UnionWordName, on_delete=models.SET_NULL, null=True)
full_address = models.CharField(max_length=200, null=True, blank=True)
create_date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s, Mobile: %s' % (self.customer_name, self.mobile_number)
def get_absolute_url(self):
return reverse('customer_data', kwargs={'pk': self.pk})
class BillingData(models.Model):
bill_no = models.CharField(max_length=100, default='', blank=True)
customer = models.ForeignKey(CustomerData, on_delete=models.CASCADE)
sales_person = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
customer_money = models.IntegerField()
create_date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s %s' % (self.customer.customer_name, self.create_date.date())
def get_absolute_url(self):
return reverse('customers.views.BillingPage', kwargs={'pk': self.pk})
forms.py file
class BillCreateForms(forms.ModelForm):
bill_no = forms.CharField(max_length=100)
customer = forms.ChoiceField(choices=[(x.id, x.customer_name) for x in CustomerData.objects.all()])
customer_money = forms.IntegerField()
def save(self, commit=True):
instance = super(BillCreateForms, self).save(commit=False)
customer_pk = self.cleaned_data['customer']
instance.customer = CustomerData.objects.get(pk=customer_pk)
instance.save(commit)
return instance
class Meta:
model = BillingData
fields = ('bill_no', 'customer', 'customer_money',)
views.py file
class CustomerDataView(FormMixin, generic.DetailView):
model = CustomerData
form_class = BillCreateForms
template_name = "customers/customerdata_detail.html"
print(form_class)
success_url = '/c/'
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
I expect data save with foreignkey relation data. But doesn't save here.

You can't fix this problem in the save method, because the error happens before it gets that far.
You should be using a ModelChoiceField, not a ChoiceField. Not only would this fix the problem, it would also let you remove your entire save method.
customer = forms.ModelChoiceField(queryset=CustomerData.objects.all())

Change this line
instance.customer = CustomerData.objects.get(pk=customer_pk)
to
instance.customer_id = CustomerData.objects.get(pk=customer_pk).pk

Model:
class Blog(models.Model):
# ...
pass
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, null=True)
Set object
b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.add(e)

Related

Django Formset: Add lines from an existing product catalog?

I have got a form with a formset that allows me to add some lines to it. I can add some simple lines. But I also wanted to add some products from a product catalog.
So the process will be as following:
User create a new purchase order (Working)
User add lines as explained below (Working)
User a button add lines from existing product catalog. The user will then browse or filter the product, he wants to order and add it to the purchase order.
I know what I am trying to do is wrong as I guess we can not have two def get_context_data(self, **kwargs): in the function. What would be the idea to be able to add products from the catalog in my formset?
Many Thanks,
Product list
models.py
class BaseProduct(models.Model):
"""
Abstract base product model class providing the base fields and methods
"""
supplier = models.CharField(max_length=300, blank=True, null=True)
manufacturer = models.CharField(max_length=300, blank=True, null=True)
product_range = models.CharField(max_length=300, blank=True, null=True)
part_number = models.CharField(_('Item Code'), max_length=255, blank=True, null=True)
description = models.CharField(_('description'), max_length=255, blank=True, null=True)
Orders
views.py
class OrderCreate(CreateView):
model = Order
template_name = 'accounting/orders/create_order.html'
form_class = OrderForm
success_url = None
def get_context_data(self, **kwargs):
data = super(OrderCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['lines'] = OrderLineFormSet(self.request.POST)
else:
data['lines'] = OrderLineFormSet()
return data
def get_context_data(self, **kwargs):
data = super(OrderCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['productlines'] = OrderProductLineFormSet(self.request.POST)
else:
data['productlines'] = OrderProductLineFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
lines = context['lines']
with transaction.atomic():
form.instance.created_by = self.request.user
self.object = form.save()
if lines.is_valid():
lines.instance = self.object
lines.save()
return super(OrderCreate, self).form_valid(form)
def get_success_url(self):
return reverse('accounting:detail_order', kwargs={'order_id': self.object.pk})
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(OrderCreate, self).dispatch(*args, **kwargs)
models.py
class OrderLine(models.Model):
order = models.ForeignKey('Order', on_delete=models.CASCADE, related_name="has_lines", blank=True, null=True)
order_item = models.CharField(max_length=100, verbose_name="Line", blank=True, null=True)
tax_rate = models.ForeignKey('TaxRate', on_delete=models.CASCADE, blank=True, null=True)
total = models.CharField(max_length=250, blank=True, null=True)
description = models.CharField(max_length=100, blank=True, null=True)
unit_price_excl_tax = models.DecimalField(max_digits=8,decimal_places=2, blank=True, null=True)
quantity = models.DecimalField(max_digits=8,decimal_places=2,default=1, blank=True, null=True)
def total(self):
total = Decimal(str(self.unit_price * self.quantity))
return total.quantize(Decimal('0.01'))
def __unicode__(self):
return self.description
class Meta:
pass
class OrderProductLine(models.Model):
order = models.ForeignKey('Order', on_delete=models.CASCADE, related_name="has_lines", blank=True, null=True)
baseproduct = models.ForeignKey('BaseProduct', on_delete=models.CASCADE, related_name="has_product_lines", blank=True, null=True)
order_item = models.CharField(max_length=100, verbose_name="Product_Line", blank=True, null=True)
tax_rate = models.ForeignKey('TaxRate', on_delete=models.CASCADE, blank=True, null=True)
total = models.CharField(max_length=250, blank=True, null=True)
description = models.CharField(max_length=100, blank=True, null=True)
unit_price_excl_tax = models.DecimalField(max_digits=8,decimal_places=2, blank=True, null=True)
quantity = models.DecimalField(max_digits=8,decimal_places=2,default=1, blank=True, null=True)
def total(self):
total = Decimal(str(self.unit_price * self.quantity))
return total.quantize(Decimal('0.01'))
def __unicode__(self):
return self.description
class Meta:
pass
forms.py
class OrderLineForm(forms.ModelForm):
class Meta:
model = OrderLine
exclude = ()
OrderLineFormSet = inlineformset_factory(
Order, OrderLine, form=OrderLineForm,
fields=['order_item', 'description','quantity','unit_price_excl_tax','tax_rate'], extra=1, can_delete=True
)
class OrderProductLineForm(forms.ModelForm):
class Meta:
model = OrderProductLine
exclude = ()
OrderProductLineFormSet = inlineformset_factory(
BaseProduct, OrderProductLine, form=OrderProductLineForm,
fields=['supplier', 'part_number','quantity','unit_price_excl_tax','tax_rate'], extra=1, can_delete=True
)
To fix the issue with your view you can combine the two get_context_data methods, but I am not sure if this will fix all the issues you are having
def get_context_data(self, **kwargs):
data = super(OrderCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['lines'] = OrderLineFormSet(self.request.POST)
data['productlines'] = OrderProductLineFormSet(self.request.POST)
else:
data['lines'] = OrderLineFormSet()
data['productlines'] = OrderProductLineFormSet()
return data
More generally, it looks like you are trying to edit two models at the same time utilizing the ModelForm class. The best way to do this is to have two model forms submit through the same form rather than utilizing formsets. There is a good example of this here taken from this SO post. You should be able to find more details on this implementation in the two links.

how to check and pass the instance of the user in my form in Django?

Hi I'm trying to create a form that accepts Log from the user however I don't know how to pass the instance of the user. I'm used to creating a CreateView for this, however since I'm planning to use customized widgets and settings, I'm using a modelform to create logs for the user.
My question is is this the same way as create view to check the instance of the user?
Is it still the same as what I did to my createview which is:
def form_valid(self,form) :
form.instance.testuser = self.request.user
return super().form_valid(form)
Or do I have to do something else entirely?
Here is my Forms.py:
from django import forms
from profiles.models import User
from .models import DPRLog
class DateInput (forms.DateInput):
input_type = 'date'
class Datefield (forms.Form):
date_field=forms.DateField(widget=DateInput)
class dprform(forms.ModelForm):
class Meta:
model = DPRLog
widgets = {'reportDate':DateInput()}
fields = ['status','login','logout','reportDate','mainTasks','remarks']
Models.py:
from django.db import models
from profiles.models import User
from django.urls import reverse
# Create your models here.
class Points(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
points = models.IntegerField(default=0, null=False)
def __str__(self):
return self.user.username
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.png', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
class Manager(models.Model):
manager = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return self.manager.full_name
class Member(models.Model):
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=30, null=True)
def __str__(self):
return self.member.full_name
class Job(models.Model):
manager = models.ForeignKey(Manager, on_delete=models.CASCADE)
member = models.ForeignKey(Member, on_delete=models.CASCADE)
title = models.CharField(max_length=30, blank=False, null=False)
description = models.TextField()
datePosted = models.DateTimeField(auto_now=True)
file = models.FileField(null=True, blank=True, upload_to='job_files')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('job-detail', kwargs={'pk': self.pk})
class DPRLog(models.Model):
STATUS_CHOICES = (
('PENDING', 'PENDING'),
('CANCELLED', 'CANCELLED'),
('COMPLETED', 'COMPLETED'),
)
TASKS_CHOICES = (
('TESTS EXECUTION', 'TESTS EXECUTION'),
('TESTS DESIGN', 'TESTS DESIGN'),
('MOBILE TESTING WORKSHOP', 'MOBILE TESTING WORKSHOP'),
('BENCH ACTIVITY', 'BENCH ACTIVITY'),
('DEFECT ANALYSIS','DEFECT ANALYSIS'),
)
testuser = models.ForeignKey(User,on_delete = models.CASCADE)
status = models.CharField(max_length=30, choices=STATUS_CHOICES,null=True)
reportDate = models.DateField(blank=False, null=False)
login = models.TimeField(blank=False, null=False)
logout = models.TimeField(blank=False, null=False)
mainTasks = models.CharField(max_length=50, blank=False, choices=TASKS_CHOICES, null=True)
remarks = models.CharField(max_length=30,null=True)
def __str__(self):
return f'{self.testuser.full_name} DPR Log'
Views.py:
def dprmodelform(request):
if request.method=='POST':
form = dprform(request.POST)
if form.is_valid():
form.save()
form = dprform()
return render (request,'users/dprform.html',{'form':form})
def form_valid(self,form) :
form.instance.testuser = self.request.user
return super().form_valid(form)
class dprview(LoginRequiredMixin,ListView):
model = DPRLog
template_name = 'users/dpr_view.html'
context_object_name = 'log'
If you pass commit=False to form.save() you can get the instance from the validated form without saving to the database. You can then set the user attribute on the instance before calling save again
if form.is_valid():
instance = form.save(commit=False)
instance.testuser = request.user
instance.save()

How to display form in django

I'am little confiused because my code in django does't work and I don't know why. I want to create a form displaying in html file. When I click on thh button, the url have to redirect me in the html file where I've put the form code. But the django return me a error
'User' object has no attribute 'nazwa_set'
My models.py is:
from django.db import models
from django.contrib.auth.models import User
class Firma(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
nazwa = models.CharField(max_length=250,verbose_name='Nazwa firmy', unique=False)
class Meta:
verbose_name = 'Firmę'
verbose_name_plural = 'Firmy'
def __str__(self):
return self.nazwa
class Cudzoziemiec(models.Model):
OBYWATELSTWA = (
('RU', 'Rosja'),
('UA', 'Ukraina'),
('BY', 'Białoruś'),
)
TYTUL_POBYTOWY = (
('WZ', 'Wiza'),
('KP', 'Karta pobytu')
)
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Użytkownik")
nazwa = models.ForeignKey(Firma, on_delete=models.CASCADE, verbose_name="Firma")
obywatelstwo = models.CharField(max_length=250,choices=OBYWATELSTWA, verbose_name="Obywatelstwo")
imie = models.CharField(max_length=80, verbose_name="Imię", unique=False)
nazwisko = models.CharField(max_length=150, verbose_name="Nazwisko", unique=False)
data_ur = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Data urodzenia")
miejsce_ur = models.CharField(max_length=100, verbose_name="Miejsce urodzenia")
paszport = models.CharField(max_length=30, verbose_name="Paszport")
data_start_pasz = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Data wydania paszportu")
data_koniec_pasz = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Data ważności paszportu")
dok_pobytowy = models.CharField(max_length=250,choices=TYTUL_POBYTOWY, verbose_name="Tytuł pobytowy")
data_start_pobyt = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Dokument pobytowy ważny od")
data_koniec_pobyt = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Dokument pobytowy ważny do")
class Meta:
verbose_name = 'Cudzoziemca'
verbose_name_plural = 'Cudzoziemcy'
def __str__(self):
return f'{self.imie} {self.nazwisko}'
in the view.py responsible def for adding the new record:
#login_required
def nowy_pracownik(request):
if request.method == "POST":
nowy_pracownik = CudzoziemiecForm(request.user, request.POST)
if nowy_pracownik.is_valid():
nowy_pracownik.save()
messages.success(request, 'Pomyślnie dodano pracownika !')
return render(request, 'cudzoziemiec/nowy_pracownik_ok.html')
else:
nowy_pracownik = CudzoziemiecForm(request.user)
return render(request, 'cudzoziemiec/nowy_pracownik.html', {'nowy_pracownik':nowy_pracownik})
And on the end here is my forms.py :
class FirmaForm(forms.ModelForm):
class Meta:
model = Firma
fields = ('nazwa',)
class CudzoziemiecForm(forms.ModelForm):
class Meta:
model = Cudzoziemiec
fields = ('nazwa','imie', 'nazwisko','obywatelstwo', 'data_ur','paszport', 'data_start_pasz', 'data_koniec_pasz', 'dok_pobytowy', 'data_start_pobyt', 'data_koniec_pobyt')
def __init__(self, user, *args, **kwargs):
super(CudzoziemiecForm, self).__init__(*args, **kwargs)
self.fields['nazwa'].queryset = user.nazwa_set.all()
self.user = user
def save(self, commit=True):
instance = super(CudzoziemiecForm, self).save(commit=False)
instance.user = self.user
if commit:
instance.save()
return instance
The error is probably somewhere in the forms. py in the class CudzoziemiecForm in line self.fields['nazwa'].queryset = user.nazwa_set.all()
In django default reverse lookup name is modelname_set. So when you trying to get user.nazwa_set.all() this means that there is some model Nazwa related with User. Since in your code you don't have model named Nazwa this line raise the error. I suppose you mean Cudzoziemiec or Firma so to fix problem you need to replace user.nazwa_set.all() with user.firma_set.all() in form's __init__ method.

Using a Django profile field to restrict queryset of a list view

I want to use a field in the Profile model of a logged in user to restrict the queryset used in a Django class based view.
My models are:
# User profile info
class Profile(models.Model):
# Relationship Fields
user = models.OneToOneField(User, on_delete=models.CASCADE)
school = models.ForeignKey('eduly.School', default=1)
notes = models.TextField(max_length=500, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
and
class School(models.Model):
# Fields
name = models.CharField(max_length=255)
address = models.TextField(max_length=500, blank=True)
email = models.CharField(max_length=30)
phone = models.CharField(max_length=15)
contactName = models.CharField(max_length=30)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('eduly_school_detail', args=(self.slug,))
def get_update_url(self):
return reverse('eduly_school_update', args=(self.slug,))
class Teacher(models.Model):
SCHOOL_ADMIN = 0
CLASS_ADMIN = 1
TASK_ADMIN = 2
ROLES = {
(SCHOOL_ADMIN, "School administrator"),
(CLASS_ADMIN, "Class administrator"),
(TASK_ADMIN, "Task administrator")
}
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
email = models.CharField(max_length=30)
roles = models.IntegerField("Role", choices=ROLES, default=1)
# Relationship Fields
school = models.ForeignKey('eduly.School', )
class Meta:
ordering = ('-created',)
def __str__(self):
return self.name
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('eduly_teacher_detail', args=(self.slug,))
def get_update_url(self):
return reverse('eduly_teacher_update', args=(self.slug,))
The view whose queryset I am trying to restrict is:
#method_decorator(login_required, name='dispatch')
class TeacherListView(ListView):
model = Teacher
def get_queryset(self):
return Teacher.objects.filter(user=self.request.user)
But instead of return Teacher.objects.filter(user=self.request.user) I want to only list Teachers who have a school the same as the school in the logged in user's Profile.
Seems like this would work:
Teacher.objects.filter(school=self.request.user.profile.school)

Include other field as choices to foreign key, Django

I have two models as follows :
class FlightSchedule(models.Model):
tail_number = models.ForeignKey(TailNumber, null=False, blank=False)
flight_number = models.CharField(max_length=30, null=False, blank=False)
flight_group_code = models.ForeignKey(FlightGroup, null=False, blank=False)
origin_port_code = models.ForeignKey(Port, null=False, related_name="Origin", blank=False)
destination_port_code = models.ForeignKey(Port, null=False, related_name="Destination", blank=False)
flight_departure_time = models.TimeField()
start_date = models.DateField()
end_date = models.DateField()
def __unicode__(self):
return u'%s' % self.flight_number
class Meta:
verbose_name_plural = "flights Schedule"
class PosFlightSchedule(models.Model):
tail_number = models.ForeignKey(TailNumber, null=False, blank=False)
pos_flight_number = models.ForeignKey(FlightSchedule, max_length=30, null=False, blank=False,
related_name='pos_flight_number')
pos_flight_departure_time = models.ForeignKey(FlightSchedule, max_length=30,
related_name='pos_flight_departure_time')
pos_route_id = models.ForeignKey(FlightScheduleDetail, null=False, blank=False, related_name='pos_route_id')
pos_flight_date = models.ForeignKey(FlightScheduleDetail, null=False, blank=False, related_name='pos_flight_date')
pax_count = models.IntegerField(null=True)
def __unicode__(self):
return u'%s' % self.pos_flight_number
class Meta:
verbose_name_plural = "Flights Schedule"
For the pos_flight_departure_time , I need the choices from flight_departure_time from the FlightSchedule class. But I get the flight_number values in the drop down. What do I have to change, to get the flight_departure_time values? The classes are from different apps in a single django project. So they have two admin files.
No you don't actually need that. You need only one foreign key in your second model to FlightScheduleDetail and you need just one foreign key to FlightSchedule
class PosFlightSchedule(models.Model):
tail_number = models.ForeignKey(TailNumber, null=False, blank=False)
flight = models.ForeignKey(FlightSchedule, null=False, blank=False,related_name='pos_flight_number')
related_name='pos_flight_departure_time')
pos_route_id = models.ForeignKey(FlightScheduleDetail, null=False, blank=False, related_name='pos_route_id')
pax_count = models.IntegerField(null=True)
def __unicode__(self):
return u'%s' % self.pos_flight_number
class Meta:
verbose_name_plural = "Flights Schedule"
Then all the fields declared in the first model automatically become available to PosFlightSchedule
So for example you can do
p = PosFlightSchedule.objects.all()[0]
print (p.flight.flight_number)
print (p.flight.pos_flight_departure_time)
etc.
This is the correct way to do it.
You may solve this by defining model form, and by not changing to models.py
class PosFlightScheduleForm(forms.ModelForm):
pos_flight_departure_time = forms.ChoiceField(label="Pos Department Time",
choices=[(i.pk, i.flight_departure_time) for i in FlightSchedule.objects.all()],
required=True)
def __init__(self, *args, **kwargs):
super(PosFlightScheduleForm, self).__init__(*args, **kwargs)
self.fields['pos_flight_departure_time'] = forms.ChoiceField(label="Pos Department Time",
choices=[(i.pk, i.flight_departure_time) for i in FlightSchedule.objects.all()],
required=False)
class Meta:
model = PosFlightSchedule
fields = (
"tail_number", 'pos_flight_departure_time',)
In view.py You may use this form
def add_view(self, request):
form = PosFlightScheduleForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/postflights')
context = {
'form': form,
}
return render(request, 'path/form.html', context)

Categories