django: foreign key issues when creating a model object - python

I am trying to write a row to database, with data gathered in a form. I need to work with two foreign keys and one of them is causing the creating to fail, although I am unable to figure out why:
here is my model:
def upload_path(instance,file):
file_dir = Path(file).stem
print('usr',instance.user.id)
path = '{}/{}/{}/{}'.format(instance.user.id,"projects",file_dir,file)
return path
class BuildingFilesVersions(models.Model):
version_id = models.AutoField(primary_key=True)
building_id = models.ForeignKey(Building, on_delete=models.CASCADE,related_name='building_id_file')
user = models.ForeignKey(Building, on_delete=models.CASCADE,related_name="user_file")
created_at = models.DateTimeField(auto_now_add=True, blank=True)
description = models.TextField(max_length=200, blank=True, null=True)
modification_type = models.CharField(choices=WORK_TYPE_CHOICES, max_length=200, blank=True, null=True)
filename = models.CharField(max_length=200, blank=True, null=True)
file = models.FileField(upload_to=upload_path, null=True, blank=True)
and here is my view:
#login_required
#owner_required
def RegisterFileView(request,pk):
form = AddBuildingFileForm()
if request.method == 'POST':
form = AddBuildingFileForm(request.POST,request.FILES)
if form.is_valid():
description = form.cleaned_data["description"]
modification_type = form.cleaned_data["modification_type"]
filename = form.cleaned_data["modification_type"]
file = request.FILES['file'].name
BuildingFilesVersions.objects.create(building_id_id=pk,
user_id=request.user,
description=description,
modification_type=modification_type,
filename=filename,
file=file)
return redirect('home')
else:
form = AddBuildingFileForm()
context = {'form':form}
return render(request, 'building_registration/register_file.html', context)
what gets me confused is that the error is Field 'building_id' expected a number but got <SimpleLazyObject: <User: Vladimir>> even though pk return the proper building_id
Can anyone see where I messed up?

to access the id of the foreign key add a double underscore
BuildingFilesVersions.objects.create(building_id=Building.objects.get(pk=pk),
user=request.user,
description=description,
modification_type=modification_type,
filename=filename,
file=file)
Your user must be logged in to assign him in the Model
Answer for Similar Question
See the Docs

Related

django: CourseNote() got an unexpected keyword argument 'user'

I'm writing a function to save notes to the database from a form but it keeps throwing this error CourseNote() got an unexpected keyword argument 'user' and I don't seem to know where this error is coming from.
views.py:
def CourseNote(request, course_slug):
course = Course.objects.get(slug=course_slug)
user = request.user
if request.method == "POST":
course = Course.objects.get(slug=course_slug)
user = request.user
note_title = request.POST.get('note_title')
note_content = request.POST.get('note_content')
# CourseNote.objects.create(user=user, course=course, note_title=note_title, note_content=note_content)
new_note = CourseNote(user=user, course=course, note_title=note_title, note_content=note_content)
new_note.save()
response = 'Saved'
return HttpResponse(response)
urls.py:
path('<slug:course_slug>/save-note', views.CourseNote, name="save-note"),
models.py:
class CourseNote(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="note_user")
course = models.ForeignKey(Course, on_delete=models.SET_NULL, null=True)
note_title = models.CharField(max_length=200, blank=True, null=True)
note_content = models.TextField(blank=True, null=True)
date = models.DateTimeField(auto_now_add=True)
#sunderam-dubey It is not good practice to name same your view and model, kindly change it

How to use default field values for ForeignKey?

I'm just starting to learn Django and building a simple blog with it.
So i have two models Post and PostStatistics. When ever i add a new post, i want that PostStatistics contains all specified default values. How can i achieve this correctly?
models.py
class PostStatistics(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
post_views = models.IntegerField(default=0)
post_likes = models.IntegerField(default=0)
post_favorites = models.IntegerField(default=0)
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
user = models.ForeignKey(UserProfile, null=True, on_delete=models.CASCADE)
statistics = models.ForeignKey(PostStatistics, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
body = RichTextField(blank=True, null=True)
draft = models.BooleanField(default=False)
views.py
def add_post(request: HttpRequest):
form = PostForm(request.POST)
is_draft = True if form.data.get("draft") == "on" else False
post = Post(
title=form.data["title"],
body=form.data["post"],
user=request.user,
draft=is_draft,
statistics = PostStatistics() -> this is not correct
)
post.save()
return redirect("post")
At the moment i get FOREIGN KEY constraint failed.
You create a new one:
def add_post(request: HttpRequest):
form = PostForm(request.POST)
is_draft = form.data.get('draft') == 'on'
post_statistics = PostStatistics.objects.create()
Post.objects.create(
title=form.data['title'],
body=form.data['post'],
user=request.user,
draft=is_draft,
statistics = post_statistics
)
return redirect('post')
It however does not make much sense to store the statistics in a separate model, since there is a clear one-to-one relation, and thus the statistics can be stored in the Post model.
Furthermore you can use the form to validate the input and also create the object (or at least parts of it). A better modeling thus might be:
from django.conf import settings
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE, editable=False)
title = models.CharField(max_length=200)
body = RichTextField(blank=True, null=True)
draft = models.BooleanField(default=False)
post_views = models.IntegerField(default=0, editable=False)
post_likes = models.IntegerField(default=0, editable=False)
post_favorites = models.IntegerField(default=0, editable=False)
and then work with a ModelForm where you let the form do all the proper validation and cleaning:
from django.contrib.auth.decorators import login_required
#login_required
def add_post(request: HttpRequest):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('post')
else:
form = PostForm()
return render(request, 'name-of-some-template.html', {'form': form})
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

How to solve ValueError Assign problem in Django?

I created a system with Django. In this system, user uploads an excel table and I creating a new customer from that excel. But in this excel I have 2 important columns. They are entity and parent. I want to when a user uploads this excel table but If there is an entity or parent that is not registered in my database, I want to create it and then save it. I user get_or_createe for that but I am getting an error:
ValueError at /customers/upload Cannot assign "(<ParentCompany:
TESTP>, False)": "Customer.parent" must be a "ParentCompany" instance.
How can I solve it?
views.py
def customer_excel_upload(request):
current_user = request.user
userP = UserProfile.objects.get_or_create(username=current_user)
company = userP[0].company
if request.method == 'POST':
form = CustomerExcelForm(request.POST, request.FILES)
if form.is_valid():
new_excel = form.save()
new_excel = new_excel.excel
df = pd.read_excel('C:/fray/otc/'
+
new_excel.name,
index_col=0,
engine='openpyxl')
for index, row in df.iterrows():
if row is not None:
new_customer = Customer()
new_customer.customer_name = index
country = Country.objects.get(country_name=row['Country'])
new_customer.address = row['Address']
new_customer.customer_number = row['Customer Number']
new_customer.phone_number = row['Phone Number']
new_customer.email_address = row['Email Adress']
new_customer.credit_limit = row['Credit Limit']
new_customer.currency_choice = row['Currency choice']
new_customer.risk_rating = row['Risk rating']
parent = ParentCompany.objects.get_or_create(parent=row['Parent Company'],
company=request.user.company)
entity = Entities.objects.get_or_create(entities=row['Entity'], company=request.user.company)
new_customer.parent = parent
new_customer.entity = entity
new_customer.country = country
new_customer.company = company
new_customer.save()
return redirect('home')
else:
form = CustomerExcelForm()
context = {
'form': form
}
return render(request, 'customer_excel_upload.html', context)
models.py
class Customer(models.Model):
customer_name = models.CharField(max_length=100)
country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, unique=False)
address = models.CharField(max_length=250),
...
parent = models.ForeignKey(ParentCompany, on_delete=models.CASCADE, blank=True, null=True)
entity = models.ForeignKey(Entities, on_delete=models.CASCADE, blank=True, null=True)
class ParentCompany(models.Model):
parent = models.CharField(max_length=50, null=True)
company = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True, unique=False)
class Entities(models.Model):
entities = models.CharField(max_length=250)
company = models.ForeignKey(CompanyProfile, on_delete=models.CASCADE, null=True, unique=False)
get_or_create doesn't return an object directly, as the error message says. You can check the docs. It returns a tuple of (object, created).
Yours is returning correctly
(<ParentCompany: TESTP>, False)
You just need to get the first part.
you can change your get_or_create statements to get the first like this:
ParentCompany.objects.get_or_create(parent=row['Parent Company'], company=request.user.company)[0]
note the [0] on the end.

Django save ManyToManyField Model with ModelMultipleChoiceField

So I know there are a few similar questions but none of the solutions worked for me. I've tried save(commit=false) and save_m2m as well as a bunch of other stuff but i get the error
NOT NULL constraint failed: home_services.managers_id
Anyways here's my code:
views.py
def service(request):
if request.user.is_authenticated:
if request.method == 'POST': #Create Service
form = CreateServiceForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/service') #Later change this to redirect to server page
else:
form = CreateServiceForm()
args = {'user': request.user, 'form': form}
return render(request, 'service.html', args)
else:
return HttpResponseRedirect('/feed')
models.py
class Services(models.Model):
name = models.CharField(max_length=100, default='')
description = models.CharField(max_length=500, default='')
owner = models.OneToOneField(User, on_delete=models.CASCADE)
managers = models.ForeignKey(User, related_name="managers", on_delete=models.CASCADE)
members = models.ManyToManyField(User, related_name="members")
def __str__(self):
return str(self.name) + ": id" + str(self.id)
forms.py
class CreateServiceForm(forms.ModelForm):
owner = forms.ModelChoiceField(queryset=User.objects.all())
members = forms.ModelMultipleChoiceField(queryset=User.objects.all())
class Meta:
model = Services
fields = [
'name',
'description',
'owner',
'members',
]
I want the user to be able to create a service and select 1 or more members that is in the default django User model.
I want the user to be able to create a service and select 1 or more members that is in the default django User model.
You are not providing managers, which is not allowed as per the current configuration.
So, change:
managers = models.ForeignKey(
User,
related_name="managers",
on_delete=models.CASCADE,
)
To:
managers = models.ForeignKey(
User,
related_name="managers",
on_delete=models.CASCADE,
blank=True,
null=True,
)
You might want to read more about blank and null.

ManyToManyField does not save in django

I have a situation again, when I do a form.save(), my form saves only the parent table, it does not save the intermediary table which is required for Many-To-Many relationships.
My models.py look like this
class Platform(models.Model):
id = models.AutoField(primary_key=True)
description = models.TextField(blank=True)
annotation_file_archived_location = models.FileField(upload_to='msrb/platform')
anntation_file_hashsum = models.TextField()
annotation = models.TextField(unique=True)
def __unicode__(self):
return self.annotation
class Meta:
managed = True
db_table = 'platform'
class Dataset(models.Model):
dataset_id = models.TextField(primary_key=True)
title = models.TextField(blank=True, null=True)
taxonomy = models.ForeignKey('Organism', blank=True, null=True)
citation = models.TextField(blank=True, null=True)
summary = models.TextField(blank=True, null=True)
contributor = models.TextField(blank=True, null=True) # This field type is a guess.
submitted = models.DateField(blank=True, null=True)
last_updated = models.DateField(blank=True, null=True)
author = models.ForeignKey('Users', db_column='author', blank=True, null=True)
platforms = models.ManyToManyField(Platform,through='DatasetPlatform')#,through_fields=('Platform:platform','dataset'))
class Meta:
managed = True
db_table = 'dataset'
class DatasetPlatform(models.Model):
id = models.IntegerField(primary_key=True)
platform = models.ForeignKey(Platform, null=False)
dataset = models.ForeignKey(Dataset,null=False)
class Meta:
managed = False
db_table = 'dataset_platform'
Forms.py
class DatasetForm(forms.ModelForm):
dataset_id = forms.CharField(required=True,help_text="dataset_id")
title = forms.CharField(required=True,help_text="title")
taxonomy = forms.ModelChoiceField(queryset=Organism.objects.all(),empty_label=None,help_text='Taxonomy')
citation = forms.CharField(required=True,help_text="citation")
summary = forms.CharField(required=True,help_text="summary")
contributor = forms.CharField(help_text="contributor (separated by comma)")
submitted = forms.DateField(initial = datetime.now,required=True,help_text="Submitted date")
last_updated = forms.DateField(initial = datetime.now,required=True,help_text="Last Updated date")
platform = forms.ModelMultipleChoiceField(queryset=Platform.objects.all(),help_text="Choose the platforms this dataset belongs to")
class Meta:
model = Dataset
fields = ('dataset_id','title','taxonomy','citation','summary','contributor','submitted','last_updated','platform')# Add author later ,'author')
views.py
def add_dataset(request):
context_dict = {}
if request.method == 'POST':
form = DatasetForm(request.POST)
if form.is_valid():
print "------------------------------------------------------------------------------"
print form.cleaned_data['platform']
form.save()
print "------------------------------------------------------------------------------"
return HttpResponseRedirect('/msrb/')
else:
print form
print form.errors
else:
form = DatasetForm()
context_dict['form'] = form
template = get_template('msrb/add_dataset.html')
context = RequestContext(request,context_dict)
return HttpResponse(template.render(context))
I have tried saving the data using
form.save(commit=True)
form.save_m2m()
form.cleaned_data gives the proper output.
I am not sure what am I missing here as I dont get an error message from django too.
EDIT
I have a workaround for the problem, but I am not sure if this is the best solution. If I can get a better solution, I will be greatful.
def add_dataset(request):
context_dict = {}
if request.method == 'POST':
form = DatasetForm(request.POST)
if form.is_valid():
print form.cleaned_data['platform']
f = form.save()
for p in form.cleaned_data['platform']: <--- Added
d = DatasetPlatform(dataset = f,platform = p) <--- Added
d.save() <--- Added
return HttpResponseRedirect('/msrb/')
else:
print form
print form.errors
else:
form = DatasetForm()
context_dict['form'] = form
template = get_template('msrb/add_dataset.html')
context = RequestContext(request,context_dict)
return HttpResponse(template.render(context))
Django is not able (well, refuses) to automatically save m2m relations with a custom through model. Saving the form data uses direct assignment to the ManyToManyField, which will not work as explained here.
If removing the custom through model is an option, I'd do that. Granted, it will have to be managed = True, but it greatly simplifies use of the field. You're not saving any extra data in the relationship, so it might be an option.
Otherwise, you have already found the only workaround. Each time you want to manipulate the m2m relationship, you'll have to manually create, alter and delete the DatasetPlatform instances. Again, this is explained in further detail in the relevant documentation.

Categories