Cannot assign foreign key with item ID - python

I am trying to auto assign a value to a foreign key, so that the model is automatically associated with another model. This is done when an entry is made by a form. I get the following error
ValueError at /nodiso/createaction/23/
Cannot assign "'23'": "LeadActions.lead" must be a "Leads" instance.
This is the two models:
class Leads(models.Model):
company = models.ManyToManyField(Company)
user = models.ManyToManyField(settings.AUTH_USER_MODEL)
name = models.CharField(max_length=265)
email = models.EmailField(max_length=265)
tel = models.IntegerField()
dateenq = models.DateField(auto_now_add=True,null=True)
def get_absolute_url(self):
return reverse('nodisoapp:leadlist')
def __str__(self):
return self.name
class LeadActions(models.Model):
lead = models.ForeignKey(Leads)
name = models.CharField(max_length=265)
crdate = models.DateField(auto_now_add=True)
Duedate = models.DateField()
creator = models.CharField(max_length=265)
overdue = models.IntegerField(null=True,blank=True)
def get_absolute_url(self):
return reverse('nodisoapp:leadlist')
def __str__(self):
return self.name
This is the View
class ActionCreateView(LoginRequiredMixin, generic.CreateView):
login_url = '/scrty/login/'
template_name = "nodiso/actioncreate.html"
form_class = forms.LeadActionCreateForm
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.lead = self.kwargs['pk']
self.object.creator = self.request.user
self.object.save()
return super(LeadCreateView, self).form_valid(form)
This is the model form
class LeadActionCreateForm(forms.ModelForm):
class Meta:
model = models.LeadActions
fields = ['name','Duedate']
I would appreciate the help.

Try this:
self.object.lead_id = self.kwargs['pk']
Since you are using the key value directly, use need to reference the variable with '_id'.
Another way is:
self.object.lead_id = Lead.objects.get(pk=self.kwargs['pk'])
Which in this case is not required, since you have the key value.

You have two problems here.
One, you need to use the lead_id field name if you have the PK of the related instance rather than an instance object.
Two, kwargs matched from the URI regexp are strings, while PK values are integers. Assuming your uris regexp is properly restrictive, you can just convert it using int. So combining the two:
self.object.lead = int(self.kwargs['pk'])

Instead of
self.object.lead = self.kwargs['pk']
try doing
lead_id = int(self.kwargs['pk'])
self.object.lead = Lead.objects.get(pk=lead_id)
When using the field name to assign relationship fields in Django, you must pass a model instance not a primary key. You could also use the primary key by doing:
lead_id = int(self.kwargs['pk'])
self.object.lead_id = lead_id

Related

Django Filter name "todo__test" is not defined

I'm trying to filter my Todos by the test_id pulled from the URL. It pulls the id from the URL but it cant seem to filter with todo__test. I have also tried "test", "Todo.test.test_id", "Todo.test". I guess I'm confused about what variable I need to filter and the Django restframework documentation doesn't explicitly show what variable to use. Their example uses "purchaser__username" which I don't understand where it comes from. https://www.django-rest-framework.org/api-guide/filtering/
class TodoList(generics.ListAPIView):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
def get_queryset(self):
test_id = self.kwargs['test_id']
return Todo.objects.filter(todo__test == test_id)
class Todo(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE)
content = models.TextField(blank=True)
order = models.IntegerField()
def __str__(self):
return self.content + ' - ' + self.test.test_name
class Meta:
ordering = ['test_id']
i guess it will be like this. you passed incorrect foreign key field name.
Todo.objects.filter(test_id='whatever_value')

My serializer that returns a 0 for Null value is not working

I'm trying to create a serializer that returns the value 0 instead of Null when API data is requested.
class MyIntegerField(serializers.IntegerField):
def to_representation(self, value):
if value is None:
return 0
return super(MyIntegerField, self).to_representation(value)
class ListSerializer(serializers.ModelSerializer):
post_count = MyIntegerField(initial=0)
class Meta:
model = Post
fields = (...,
'post_count',
...)
model.py:
post_count = models.IntegerField(blank=True, null=True)
If a user has no posts, then I would like to return the value 0, instead of Null.
What is the issue with my current serializer? I think the field that's inputted is still pulling from my model field, and not the new serializer function.
Currently I'm still receiving a Null when user requests data.
Using SerializerMethodField instead
class ListSerializer(serializers.ModelSerializer):
post_count = serializers.SerializerMethodField()
class Meta:
model = Post
fields = (...,
'post_count',
...)
def get_post_count(self, obj):
if obj.post_count:
return obj.post_count
return 0

How can I display the values from a ManyToMany Field in Django instead of their Id?

I have two models
Influencer
class Influencer(models.Model):
full_name = models.CharField('Full Name',max_length=255)
username = models.CharField('Username',max_length=255,unique=True)
photo = models.URLField(blank=True,max_length = 500)
email_id = models.EmailField('Email Id',blank=True,max_length=500)
categories = models.ManyToManyField(Category,blank=True,max_length=400)
and
2. Categories
class Category(models.Model):
name = models.CharField(max_length=400)
def __str__(self):
return self.name
Influencer has a many to many field categories.
My views functions to display all the influencers is:
def index(request):
influencers = Influencer.objects.all().order_by('followers')
paginator = Paginator(influencers,16)
page = request.GET.get('page')
paged_listings = paginator.get_page(page)
user_list = UserList.objects.all().filter(user_id = request.user.id)
queryset = list(chain(paged_listings,user_list))
ser_query = serializers.serialize('json', queryset)
return HttpResponse(ser_query,content_type='application/json')
The HttpResponse contains category id's instead of category names, something like this:
where categories is an array which contains category id's.
I want to display the name of categories instead of their id's.
I think this can be achived using Django Rest Framework nested serializer, but at this moment I am not using DRF.
there is an natural_key method in django to convert id to string
add natural_key method in your models.py file
class Category(models.Model):
name = models.CharField(max_length=400,)
def __str__(self):
return self.name
def natural_key(self):
return self.name
and then in your serializers.serializer you need to pass use_natural_foreign_keys=True,
ser_query = serializers.serialize('json', influencers,indent=2,use_natural_foreign_keys=True,)
convert your array element --integer value -- into string then access from a dict or a tuple which contains categories with their ids
id_to_category=["0":"whatever your category is","1":"whatever your category is","2":"whatever your category is","3":"whatever your category is"]
id=str(ur_array[id])
category_name=id_to_category[id]

The instant type changes to int in Foreign Key in Django

This is my models.py in django
class Site(models.Model):
# Site ID
siteID = models.CharField(max_length=255, null=True, unique = True)
def __str__(self):
return "{} ".format(self.siteID,)
class EndDevice(models.Model):
edevID = models.CharField(max_length=255)
siteID = models.ForeignKey(Site, on_delete=models.CASCADE)
deviceCategory = models.BigIntegerField()
And this is the method to post in views.py:
class RegisterSite(generics.ListAPIView):
'''
GET site/
POST site/
'''
queryset = Site.objects.all()
serializer_class = DataSerializer
# POST Regisger Site
def post(self, request, *args, **kwargs):
a_site = Site.objects.create(
siteID=request.data["siteID"],
# edevID=request.data["edevID"]
)
return Response(
data=DataSerializer(a_site).data,
status=status.HTTP_201_CREATED
)
class RegisterDevice(generics.ListAPIView):
'''
GET device/
POST device/
'''
queryset = EndDevice.objects.all()
serializer_class = DeviceSerializer
def post(self, request, *args, **kwargs):
siteID, created = Site.objects.get_or_create(
siteID=request.data["siteID"],
)
a_site = EndDevice.objects.create(
edevID=request.data["edevID"],
siteID = siteID,
deviceCategory=request.data["deviceCategory"],
)
return Response(
data=DeviceSerializer(a_site).data,
status=status.HTTP_201_CREATED
)
So what I am trying t do here is use the siteID from class Site for class EndDevice. But when I enter/ chose the value of siteID in Enddevice it changes to integer value. I checked the data base and it shows me int as its (siteID in EndDevice) characteristics. I was wondering how could I get the real value of siteID instead of an integer value.And I can accept character values while posting for class Site.
If the question is vague or unclear, please update me.
Thanks
EDIT
enter image description here
The serializer looks like:
class DataSerializer(serializers.ModelSerializer):
class Meta:
model = Site
fields = ("siteID",)
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = EndDevice
fields = ("edevID", "siteID", "deviceCategory")
Q:
when I enter/ chose the value of siteID in Enddevice it changes to integer value
Well the reason why it gets converted to int is because you haven't specified your own primary key field so Django uses its default primary key as Id field which is an integer field.
A:
Inside of Site model change this:
siteID = models.CharField(max_length=255, null=True, unique = True)
to this:
siteID = models.CharField(max_length=255, primary_key = True)
Now what that does is that it sets siteID as your primary_key instead of django's default Id.
See the docs

Python convert string to class

I want to do a query on the django User table like this:
u = User.objects.filter(member__in = member_list)
where:
class Member(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dob = models.DateField('Date of Birth', blank=True, null=True)
and member_list is a list of eligible members.
The query works fine but the problem is I do not actually know the model member is called member. It could be called anything.
I store the name of the model I want in a model called Category. I have a link to the name of the model through content_type.Category is defined as:
class Category(models.Model):
name = models.CharField('Category', max_length=30)
content_type = models.ForeignKey(ContentType)
filter_condition = JSONField(default="{}", help_text=_(u"Django ORM compatible lookup kwargs which are used to get the list of objects."))
user_link = models.CharField(_(u"Link to User table"), max_length=64, help_text=_(u"Name of the model field which links to the User table. 'No-link' means this is the User table."), default="No-link")
def clean (self):
if self.user_link == "No-link":
if self.content_type.app_label == "auth" and self.content_type.model == "user":
pass
else:
raise ValidationError(
_("Must specify the field that links to the user table.")
)
else:
if not hasattr(apps.get_model(self.content_type.app_label, self.content_type.model), self.user_link):
raise ValidationError(
_("Must specify the field that links to the user table.")
)
def __unicode__(self):
return self.name
def _get_user_filter (self):
return str(self.content_type.app_label)+'.'+str(self.content_type.model)+'.'+str(self.user_link)+'__in'
def _get_filter(self):
# simplejson likes to put unicode objects as dictionary keys
# but keyword arguments must be str type
fc = {}
for k,v in self.filter_condition.iteritems():
fc.update({str(k): v})
return fc
def object_list(self):
return self.content_type.model_class()._default_manager.filter(**self._get_filter())
def object_count(self):
return self.object_list().count()
class Meta:
verbose_name = _("Category")
verbose_name_plural = _("Categories")
ordering = ('name',)
So I can retrieve the name of the model that links to User but I then need to convert it into a class which I can include in a query.
I can create an object x = category.content_type.model_class() which gives me <class 'cltc.models.Member'> but when I them perform a query s = User.objects.filter(x = c.category.object_list()) I get the error Cannot resolve keyword 'x' into field.
Any thoughts most welcome.
The left hand side of the filter argument is a keyword, not a python object, so x is treated as 'x', and Django expects a field called x.
To get around this, you can ensure that x is a string, and then use the python **kwarg syntax:
s = User.objects.filter(**{x: c.category.object_list()})
Thanks to https://stackoverflow.com/a/4720109/823020 for this.

Categories