__init__() got an unexpected keyword argument - python

I'm trying to build a web service, but I'm stuck with my models. I have made a Model "User" and it has a ListField() as photos, "Photo" is an embedded document. But while saving this user object I get an error as :
Traceback (most recent call last):
File "E:\Challenge\trial\services\workspace\Service\src\appservices\trial.py",
line 7, in <module>
likedBy=["Name1", "Name2", "Name3", "Name4"]))
File "E:\Challenge\trial\Python27\lib\site-packages\djangotoolbox\fields.py",
line 253, in __init__
super(EmbeddedModelField, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'likedBy'
Below is my models file:
from django.db import models
from djangotoolbox.fields import ListField, EmbeddedModelField
class User(models.Model):
username = models.CharField(max_length=100, blank=False, unique = True)
fname = models.CharField(max_length=100, blank=False)
lname = models.CharField(max_length=100, blank=True)
photos = ListField() #embedded list of photos uploaded by users
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.name
class Photo(EmbeddedModelField):
description = models.TextField()
link = models.TextField()
like = models.IntegerField
likedBy = ListField()
def __unicode__(self):
return self.name
And the way I'm trying to save the User object is:
user = User(username="username", fname="Harshal", lname="Tripathi")
user.photos.append(Photo(description="This is a great photo uploaded for trial", link="http://image.com/images/user_photo.jpg", like="365", likedBy=["Name1", "Name2", "Name3", "Name4"]))
user.save()

This looks to me like nothing more than a normal Python issue. You've subclassed from EmbeddedModelField, but you've not overridden the init method in your subclass. As a result, when you instantiate that class providing arguments specific to your subclass, those are being fed directly to the base class's init, which is then bombing out.
At a glance at Django docs, you'll want to override init and process your class-specific args/kwargs and pass any generic/common arguments up to the base class (snippet from the docs below the following example).
I'm not a Django dev, and do not have time to get it installed and setup, but based on your provided code above, I would expect the following to work unless there's something inherent to Django that I'm not privy to and don't see at a glance in the docs.
from django.db import models
from djangotoolbox.fields import ListField, EmbeddedModelField
class User(models.Model):
username = models.CharField(max_length=100, blank=False, unique = True)
fname = models.CharField(max_length=100, blank=False)
lname = models.CharField(max_length=100, blank=True)
photos = ListField() #embedded list of photos uploaded by users
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.name
class Photo(EmbeddedModelField):
description = models.TextField()
link = models.TextField()
like = models.IntegerField
likedBy = ListField()
def __init__(self, link=None, like=None, likedBy=None, *args, **kwargs):
super(Photo, self).__init__(*args, **kwargs)
self.link = link or self.link
self.like = like or self.like
self.likedBy = likedBy or self.likedBy
def __unicode__(self):
return self.name
Writing a field subclass¶
When planning your Field subclass, first give some thought to which
existing Field class your new field is most similar to. Can you
subclass an existing Django field and save yourself some work? If not,
you should subclass the Field class, from which everything is
descended.
Initializing your new field is a matter of separating out any
arguments that are specific to your case from the common arguments and
passing the latter to the __init__() method of Field (or your parent
class).
In our example, we’ll call our field HandField. (It’s a good idea to
call your Field subclass Field, so it’s easily identifiable
as a Field subclass.) It doesn’t behave like any existing field, so
we’ll subclass directly from Field:
from django.db import models
class HandField(models.Field):
description = "A hand of cards (bridge style)"
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
super(HandField, self).__init__(*args, **kwargs)

Related

How to access the field of a model which sits in 2 ForeignKey connections to the model, from where it being accessed?

So I have 3 models which are chain connected to each other via ForeignKey and inside the Lesson model I want to create a file path to upload videos to like this courses/COURSE_NAME/SECTION_NAME, where uppercase letters are variables which should be replaced with the actual course name and section name, I don't have any problems with accessing the section name using section.name, but when I try to access the course name using the same approach section.course.name I get an error. Here is my models code:
class Course(models.Model):
name = models.CharField(max_length=80)
...
class Section(models.Model):
name = models.CharField(max_length=80)
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='sections')
...
class Lesson(models.Model):
name = models.CharField(max_length=80)
section = models.ForeignKey(Section, on_delete=models.CASCADE)
video = models.FileField(upload_to=f'courses/{section.course.name}/{section.name}/')
Error occurs in this part of code:
video = models.FileField(upload_to=f'courses/{section.course.name}/{section.name}/')
Here's the error message that I get:
video = models.FileField(upload_to=f'courses/{section.course.name}/{section.name}/')
AttributeError: 'ForeignKey' object has no attribute 'course'
Thanks in advance!!!
Edit 1:
So in process of thinking how to do this I came up with idea maybe there's a way to create a set_up method which will be run after the initialization of a course foreign key but before video file field. This set up method can treat self like you would treat an instance of a Lesson class so I tried to implement this using an __init__ method:
class Lesson(models.Model):
name = models.CharField(max_length=80)
section = models.ForeignKey(Section, on_delete=models.CASCADE)
section_id = None
def __init__(self, *args, **kwargs):
self.section_id = self.section.id
super(Lesson, self).__init__(args=args, kwargs=kwargs)
video = models.FileField(upload_to=f'courses/{section_id}/')
Project runs normally but when I go to the admin pannel and try to edit Lesson database server gives me this error:
'Lesson' object has no attribute '_state'
I did my research and found out that's because you can't just call an init method of models.Model. At least that's how I understood it.
Try doing this:
x = Lesson.objects.get(pk=1)
print('SECTION_NAME', x.section)
print('COURSE_NAME', x.section.course)
Update 19.12.2022
Based on the Lesson model and its pk, I tried to get data from the Section model, as follows, the first option with one value, the second with several:
aaa = Section.objects.filter(lesson__pk=1).all()
print('name', aaa)
print('course', aaa[0].course)
bbb = Section.objects.filter(lesson__pk__in=[1, 2]).all()
print('QuerySet more than one value', bbb)
for a in bbb:
print('id', a.id, 'course', a.course)
Update 24.12.2022
Perhaps the following will help you: pass the result returned by the function to upload_to.
def directory(instance, filename):
return '{0}/{1}/{2}'.format(instance.section.name, instance.section.course, filename)
class Lesson(models.Model):
name = models.CharField(max_length=80)
section = models.ForeignKey(Section, on_delete=models.CASCADE)
video = models.FileField(upload_to=directory, blank=True)
def __str__(self):
return self.name

Django model modification

Ok, i have this django app, where the user fills in their detail and then create a web profile(username and password)
from django.db import models
class UserDetail(models.Model):
first_name = models.CharField(max_length=225)
middle_name = models.CharField(max_length=255, blank=True, null=True)
last_name = models.CharField(max_length=255)
email = models.EmailField()
def __str__(self):
return self.first_name
class WebDetail(UserDetail):
# user = models.OneToOneField(UserDetail, on_delete=models.CASCADE, primary_key=True,)
username = models.CharField(max_length=255)
password = models.CharField(max_length=255)
and when i create a user that has a webdetail, it shows empty in the database(django admin)
I need help to link the WebDetail to inherit from the userdetail and also they could show up in the database(django admin)
Thanks for your contribution :)
I found this article on model inheritance and there was this comment at the end of the article that stated the following:
"Whoever is reading this in the future make sure you add the following method to each product type class e.g:
class Label(Product):
objects = LabelManager()
class Meta:
proxy = True
def save(self, *args, **kwargs):
self.product_type = 'Label'
return super(Label, self).save(*args, **kwargs)
Otherwise you won't be able to see your object after it's creation. Cheers :)"
Here's the link to the article. It's all on model inheritance and it looks like the above code should help with your problem of an empty database after you create a user that has a WebDetail. I would try adding something similar to your WebDetail class.

Timezone.now throwing a Type Error when overriding a save method

I am writing an API in Django Rest Framework- when using the POST method to create a new object, if the 'done' field is True and the 'done_date' is Null, I would like the 'done_date' to automatically be set to current time. Here's what I tried to do, overriding the save method in my models:
In models.py
from django.db import models
from django.utils import timezone
class Task(models.Model):
title = models.CharField(max_length=100)
done = models.BooleanField(default=False)
author_ip = models.GenericIPAddressField()
created_date = models.DateTimeField(default=timezone.now)
done_date = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ('id',)
def __str__(self):
return '{} - {}'.format(self.pk, self.title)
def save(self, *args, **kwargs):
if self.done and not self.done_date:
self.done_date = timezone.now
super(Task, self).save(*args, **kwargs)
However, this throws a "TypeError when calling Task.objects.create(). This may be because you have a writable field on the serializer class that is not a valid argument to Task.objects.create(). You may need to make the field read-only, or override the TaskSerializer.create() method to handle this correctly."
Now, I am fairly certain that it's related to timezone.now in the save method, could someone advise me on how to proceed? I apologise if it is a basic question, thanks!
All you have to do is to call the timezone.now() function (with the parenthesis)
alternatively, you could use: auto_now=True and set editable=True

Django - Get Object with ForeignKey

versions:
Python 3.4
Django 1.7
I created a gallery app with different galleries and their own images.
my models:
from django.db import models
class Gallery(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateTimeField('publish date')
def __str__(self):
return self.title
class Image(models.Model):
title = models.CharField(max_length=200)
gallery = models.ForeignKey(Gallery)
pub_date = models.DateTimeField('publish date')
file = models.ImageField(upload_to='img/gallery/'+str(Gallery.objects.get(pk=str(gallery)).id)+'/')
def __str__(self):
return self.title
you see my Gallery and Image model. While creating an Image in the Backend it should create a folder dynamicly in "img/gallery/gallery_id"
my problem is that Image.gallery is a ForeignKey here and I cant convert it into a int or string to use it. Is there a function to get the ID from my Gallery object with the ForeignKey from my Image object?
my solution
Gallery.objects.get(pk=str(gallery)).id
is not working.
btw: I thought foreignkey is always an int like id? isnt it?
The way Django works, a convenient method is automatically added that will give you the model instance that the foreign key represents. This is your gallery field. There is another field, called the same but with _id appended, that holds the actual foreign key value.
As petkostas said, you can pass a function that accepts the instance and filename arguments. You should use gallery_id instead of gallery.id to prevent an unnecessary call to the database.
def gallery_folder(instance, filename):
return '/'.join(['img/gallery', instance.gallery_id, filename])
class Image(models.Model):
...
file = models.ImageField(upload_to=gallery_folder)
upload to can be a callback:
https://docs.djangoproject.com/en/1.6/ref/models/fields/#django.db.models.FileField.upload_to
so:
def gallery_folder(instance, filename):
return '/'.join(['img/gallery', instance.gallery.id, filename])
class Image(models.Model):
title = models.CharField(max_length=200)
gallery = models.ForeignKey(Gallery, related_name='images')
pub_date = models.DateTimeField('publish date')
file = models.ImageField(upload_to=gallery_folder)
def __str__(self):
return self.title
Also add related_name, makes reverse queries easier, also you can opt for instance.gallery.title if you want.

In django, how can I retrieve a value from db into a custom field template?

I am using a custom class on my model to provide image uploading, through an app called django-filebrowser.
# myapp/models.py
class Book(models.Model):
name = models.CharField(max_length=30)
image = FileBrowseField("Image", max_length=200, blank=True, null=True)
...
The model uses filebrowser's custom field "FileBrowserField", which adds a link to a separate upload page (http://site/admin/filebrowser/browse/?ot=desc&o=date). What I'd like to do is to tweak the custom form's template to add a "dir" parameter, like so: (http://site/admin/filebrowser/browse/?ot=desc&o=date&dir=book1). book1, in this case, would be retrieved from the "name" CharField of this Book.
I know that the template that I want to modify is rendered by filebrowser's fields.py, and there is a variable that sets the "dir" parameter, but I don't know how to fetch the string value from my own model to fields.py so I can set this variable. Does anyone have any suggestions?
Found a solution elsewhere, so I thought I'd share it:
# models.py
class Book(models.Model):
name = models.CharField(max_length=30)
image = FileBrowseField("Image", max_length=200, blank=True, null=True)
...
def __init__(self, *args, **kargs):
super(Property, self).__init__(*args, **kargs)
self._meta.get_field_by_name("image")[0].directory = self.name

Categories

Resources