Django Can't save record with ForeinKey - python

I am familiar with the Django and I am using Django framework(2.2.2) in one of my website, But I am getting one weird issue for saving record with the foreign key:
I have following two models
class quick_note(models.Model):
note_id = models.AutoField(primary_key=True)
meeting_date = models.DateField(max_length=55)
title = models.TextField(blank = True,null=True)
headline = models.TextField(blank = True,null=True)
class quick_note_details(models.Model):
meeting_id = models.ForeignKey(quick_note,on_delete = models.CASCADE)
summary = models.TextField(default='',null=True)
Following is the code I have used for saving:
quick_note_details_data = quick_note_details(summary = summary_data,meeting_id = 1)
quick_note_details_data.save()
Using this I am getting following error:
ValueError: Cannot assign "2": "quick_note_details.meeting_id" must be a "quick_note" instance.
Then, I have tried the following approach suggested in the following question,
Django: ValueError when saving an instance to a ForeignKey Field
quick_note_obj = quick_note.objects.get(note_id = note_id)
quick_note_details_data = quick_note_details(summary = summary_data,meeting_id = quick_note_obj)
quick_note_details_data.save()
Using this I am getting following error:
django.db.utils.ProgrammingError: column "meeting_id_id" of relation "website_quick_note_details" does not exist
LINE 1: INSERT INTO "website_quick_note_details" ("meeting_id_id", "...
I don't have a column like meeting_id_id in the model anywhere, then why I am getting this error?
I have been searching for this long time, but didn't get any solution,
Hope I will get help here.

change meeting_id to meeting_id_id , try following
quick_note_details_data = quick_note_details(summary = summary_data,meeting_id_id = 1)

So, I had got my answer days back, so decided to answer so this will help people like me,
Basically, Django appends a suffix to the foreign_key columns,
e.g if your columns name is note ,Django will assume this as note_id,
So,To avoid this I had done only the following:
note_id = models.ForeignKey(quick_note,on_delete = models.CASCADE,db_column='note_id')
By using db_column property, now the foreign key will refer as note_id,
This solves my issue.

Related

Django Rest Framework issue in def create method..facing null value in trial end field

There is a trial end field in subscription model, i want to initialize the field with trial_end_date ,
problem I'm facing now trial_end in subscription model showing null value, How can I extract out the field of trial end field and initialize it? I have attached the def create method looked at that.
I will appreciate your help .
def create(self, validated_data):
subscriptions_data = validated_data.pop('plan')
print(subscriptions_data)
user_memberships = UserMembership.objects.create(**validated_data)
trial_end = user_memberships.membership.get_trial_period_days()
trial_end_date = datetime.date.today() + datetime.timedelta(trial_end)
for subscription_data in subscriptions_data:
Subscription.objects.create(user_membership=user_memberships, **subscription_data,)
return user_memberships
[Model][2]
my aim is when in membership model plan contain trial period days , it will add in trial end field of subscription model
Probably because you are not passing trial_end_date's value in Subscription.objects.create(..). So you can fix it like this:
trial_end = user_memberships.membership.get_trial_period_days()
trial_end_date = datetime.date.today() + datetime.timedelta(trial_end)
for subscription_data in subscriptions_data:
Subscription.objects.create(trial_end = trial_end_date, user_membership=user_memberships, **subscription_data,)

Associate classes with django-filters

Bonjour, I have a question regarding django-filters. My problem is:
I have two classes defined in my models.py that are:
class Volcano(models.Model):
vd_id = models.AutoField("ID, Volcano Identifier (Index)",
primary_key=True)
[...]
class VolcanoInformation(models.Model):
# Primary key
vd_inf_id = models.AutoField("ID, volcano information identifier (index)",
primary_key=True)
# Other attributes
vd_inf_numcal = models.IntegerField("Number of calderas")
[...]
# Foreign key(s)
vd_id = models.ForeignKey(Volcano, null=True, related_name='vd_inf_vd_id',
on_delete=models.CASCADE)
The two of them are linked throught the vd_id attribute.
I want to develop a search tool that allows the user to search a volcano by its number of calderas (vd_inf_numcal).
I am using django-filters and for now here's my filters.py:
from .models import *
import django_filters
class VolcanoFilter(django_filters.FilterSet):
vd_name = django_filters.ModelChoiceFilter(
queryset=Volcano.objects.values_list('vd_name', flat=True),
widget=forms.Select, label='Volcano name',
to_field_name='vd_name',
)
vd_inf_numcal = django_filters.ModelChoiceFilter(
queryset=VolcanoInformation.objects.values_list('vd_inf_numcal', flat=True),
widget=forms.Select, label='Number of calderas',
)
class Meta:
model = Volcano
fields = ['vd_name', 'vd_inf_numcal']
My views.py is:
def search(request):
feature_list = Volcano.objects.all()
feature_filter = VolcanoFilter(request.GET, queryset = feature_list)
return render(request, 'app/search_list.html', {'filter' : feature_filter, 'feature_type': feature_type})
In my application, a dropdown list of the possible number of calderas appears but the search returns no result which is normal because there is no relation between VolcanoInformation.vd_inf_numcal, VolcanoInformation.vd_id and Volcano.vd_id.
It even says "Select a valid choice. That choice is not one of the available choices."
My question is how could I make this link using django_filters ?
I guess I should write some method within the class but I have absolutely no idea on how to do it.
If anyone had the answer, I would be more than thankful !
In general, you need to answer two questions:
What field are we querying against & what query/lookup expressions need to be generated.
What kinds of values should we be filtering with.
These answers are essentially the left hand and right hand side of your .filter() call.
In this case, you're filtering across the reverse side of the Volcano-Volcano Information relationship (vd_inf_vd_id), against the number of calderas (vd_inf_numcal) for a Volcano. Additionally, you want an exact match.
For the values, you'll need a set of choices containing integers.
AllValuesFilter will look at the DB column and generate the choices from the column values. However, the downside is that the choices will not include any missing values, which look weird when rendered. You could either adapt this field, or use a plain ChoiceFilter, generating the values yourself.
def num_calderas_choices():
# Get the maximum number of calderas
max_count = VolcanoInformation.objects.aggregate(result=Max('vd_inf_numcal'))['result']
# Generate a list of two-tuples for the select dropdown, from 0 to max_count
# e.g, [(0, 0), (1, 1), (2, 2), ...]
return zip(range(max_count), range(max_count))
class VolcanoFilter(django_filters.FilterSet):
name = ...
num_calderas = django_filters.ChoiceFilter(
# related field traversal (note the connecting '__')
field_name='vd_inf_vd_id__vd_inf_numcal',
label='Number of calderas',
choices=num_calderas_choices
)
class Meta:
model = Volcano
fields = ['name', 'num_calderas']
Note that I haven't tested the above code myself, but it should be close enough to get you started.
Thanks a lot ! That's exactly what I was looking for ! I didn't understand how the .filter() works.
What I did, for other attributes is to generate the choices but in a different way. For instance if I just wanted to display a list of the available locations I would use:
# Location attribute
loc = VolcanoInformation.objects.values_list('vd_inf_loc', flat=True)
vd_inf_loc = django_filters.ChoiceFilter(
field_name='vd_inf_vd_id__vd_inf_loc',
label='Geographic location',
choices=zip(loc, loc),
)

How to create a custom AutoField primary_key entry within Django

I am trying to create a custom primary_key within my helpdesk/models.py that I will use to track our help desk tickets. I am in the process of writing a small ticking system for our office.
Maybe there is a better way? Right now I have:
id = models.AutoField(primary_key=True)
This increments in the datebase as; 1, 2, 3, 4....50...
I want to take this id assignment and then use it within a function to combine it with some additional information like the date, and the name, 'HELPDESK'.
The code I was using is as follows:
id = models.AutoField(primary_key=True)
def build_id(self, id):
join_dates = str(datetime.now().strftime('%Y%m%d'))
return (('HELPDESK-' + join_dates) + '-' + str(id))
ticket_id = models.CharField(max_length=15, default=(build_id(None, id)))
The idea being is that the entries in the database would be:
HELPDESK-20170813-1
HELPDESK-20170813-2
HELPDESK-20170814-3
...
HELPDESK-20170901-4
...
HELPDESK-20180101-50
...
I want to then use this as the ForeignKey to link the help desk ticket to some other models in the database.
Right now what's coming back is:
HELPDESK-20170813-<django.db.models.fields.AutoField>
This post works - Custom Auto Increment Field Django Curious if there is a better way. If not, this will suffice.
This works for me. It's a slightly modified version from Custom Auto Increment Field Django from above.
models.py
def increment_helpdesk_number():
last_helpdesk = helpdesk.objects.all().order_by('id').last()
if not last_helpdesk:
return 'HEL-' + str(datetime.now().strftime('%Y%m%d-')) + '0000'
help_id = last_helpdesk.help_num
help_int = help_id[13:17]
new_help_int = int(help_int) + 1
new_help_id = 'HEL-' + str(datetime.now().strftime('%Y%m%d-')) + str(new_help_int).zfill(4)
return new_help_id
It's called like this:
help_num = models.CharField(max_length=17, unique=True, default=increment_helpdesk_number, editable=False)
If gives you the following:
HEL-20170815-0000
HEL-20170815-0001
HEL-20170815-0002
...
The numbering doesn't start over after each day, which is something I may look at doing. The more I think about it; however, I am not sure if I even need the date there as I have a creation date field in the model already. So I may just change it to:
HEL-000000000
HEL-000000001
HEL-000000002
...

Django IntegerField returns ExpressionNode

I got a model containing two counters :
class MyObject(models.Model):
...
student_c = models.PositiveIntegerField(default=0, blank=True, null=True)
company_c = models.PositiveIntegerField(default=0, blank=True, null=True)
def total_followers(self):
return self.student_c + self.company_c
one is working perfectly and returns an integer value but the other one returns :
django.db.models.expressions.ExpressionNode object at 0x7ff4d8320a10
I tried to change PositiveIntegerField to IntegerField and to rename the field with another name but I still get the same result ? I destroyed the database and rebuilt it many times
In my template I can see this : (+: (DEFAULT: ), 1)
In fact I'm trying to do an atomic increment like this:
project = get_object_or_404(Project, pk=kwargs['pk'])
project.student_c = F('student_c') + 1
project.save(update_fields=['student_c']) or even just project.save()
This is where the problem is coming from. I looked there and I found the same code :
Atomic increment of a counter in django
What am I doing wrong ?
Any help would be very appreciated.
Thanks
I'm not sure you're using the F() object correctly. Have you tried just doing
Projects.objects.filter(pk=kwargs['pk']).update(student_c=F('student_c') + 1)
That would replace those three lines. Also you could try this for the second line:
project.student_c = project.student_c + 1
I don't know if this is similar to your problem, but maybe can help you
http://www.voidspace.org.uk/python/weblog/arch_d7_2011_04_30.shtml
Maybe you need to call .save before call total_followers in your view...
For example:
import model.MyObject
myObj = MyObject.objects.create(....)
myObj.save()
myObj.total_followers()

filter queryset based on list, including None

I dont know if its a django bug or a feature but i have a strange ORM behaviour with MySQL.
class Status(models.Model):
name = models.CharField(max_length = 50)
class Article(models.Model)
status = models.ForeignKey(status, blank = True, null=True)
filters = Q(status__in =[0, 1,2] ) | Q(status=None)
items = Article.objects.filter(filters)
this returns Article items but some have other status than requested [0,1,2,None]
looking at the sql query :
SELECT [..] FROM `app_article` LEFT OUTER JOIN `app_status` ON (`app_article`.`status_id` = `app_status`.`id`) WHERE (`app_article`.`status_id` IN (1, 2) OR `app_status`.`id` IS NULL) ORDER BY [...]
the OR app_status.id IS NULL part seems to be the cause. if i change it to OR app_article.status_id IS NULL it works correctly.
How to deal with this ?
Thanx.
Try using this query instead:
filters = Q(status__in =[0, 1,2] ) | Q(status__isnull=True)
In your foreign key attribute for the Article model, you're referencing status with a lowercase 's'. But your Status model has an uppercase 'S'. Not sure where your typo is, but in case your model is actually defined with a lower case 's', then that might explain the strange SQL you're seeing.

Categories