Django - Get Object with ForeignKey - python

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.

Related

How to generate slug based on title of post in django?

I am working on a project where I want to create a slug for each post based on its title. Is it possible to generate a slug in such a way that it will be unique to the post, but will not change even if the title of the post is changed? I am using the model provided in the file 'model.py'. Can you provide guidance on how to accomplish this?
class Post(models.Model):
username = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
description = models.CharField(('Description'),max_length=250)
title = models.CharField(('Content Title'), max_length=250)
create_date = models.DateTimeField(default = timezone.now)
image_data = models.ImageField(upload_to='User_Posts', height_field=None, width_field=None, max_length=None)
slug = (title)
def __str__(self):
return self.title
I recommend checking out the Django documentation for slugify. You will need to override the save method of your model to do this, so your new code will most likely look something like this:
from django.utils.text import slugify
slug=models.SlugField()
def save(self,*args,**kwargs):
self.slug=slugify(self.title)
super(Post,self).save(*args,**kwargs)
I would keep in mind the unique parameter that you can set to either true or false in your slugfield.

django reverse lookup foreignkey not working

I want to get a specific Video object and then find all of the Rating objects that are associated with it using ForeignKey reverse lookup as described in the docs.
I have models:
class Video(models.Model):
...
rating_int = models.IntegerField(default=1, choices=CHOICES, name='rating_int')
def __str__(self):
return self.title
class Rating(models.Model):
video = models.ForeignKey('Video', related_name='video', null=True)
and views:
def video_ratings(request):
vid_rate = Video.objects.get(pk=1)
ratings_of_video = vid_rate.rating_set.all()
context = {
'vid_rate': vid_rate, 'ratings_video': ratings_of_video
}
return HttpResponse(template.render(context, request))
When I try to run this I get an error 'Video' object has no attribute 'rating_set'
But when i read the django docs it tells me when you do a reverse lookup you need to use this _set.all() command. I am not sure what is missing here.
You have specified related_name in your foreign key loopkup. so rating_set should not work now.
You can lookup like
ratings_of_video = vid_rate.video.all()
A better naming convention will be to use ratings in your related_name
class Rating(models.Model):
video = models.ForeignKey('Video', related_name='ratings', null=True)
and then query like
ratings_of_video = vid_rate.ratings.all()

__init__() got an unexpected keyword argument

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)

Django - NameError: name 'Post' is not defined in many to many relationship

I'm very new to Python and Django. I'm trying to create a basic blog engine containing categories, posts and tags.
A category will have multiple posts
A post will have multiple tags
So i designed my models like this:
from django.db import models
class Category(models.Model):
category_name = models.CharField(max_length=200)
posts = models.ManyToManyField(Post)
def __str__(self):
return self.category_name
class Post(models.Model):
post_title = models.CharField(max_length=200)
post_body = models.TextField()
post_tags = models.ManyToManyField(Tag)
def __str__(self):
return self.post_title
class Tag(models.Model):
tag_title = models.CharField(max_length=200)
def __str__(self):
return self.tag_title
When i run python manage.py migrate command, i am getting
File "/Development/Projects/pBlog/blogEngine/models.py", line 6, in Category
posts = models.ManyToManyField(Post)
NameError: name 'Post' is not defined
Error. Is there any syntax error? I have .Net background i might need to change my whole approach.
The Post class is not yet defined when you refer to it on line 6. In this situation, you should use the name of the model instead:
class Category(models.Model):
category_name = models.CharField(max_length=200)
posts = models.ManyToManyField("Post")
def __str__(self):
return self.category_name
This is documented here: https://docs.djangoproject.com/en/1.7/ref/models/fields/#django.db.models.ForeignKey.
The problem is that you have defined class Category before you defined class Post - and you are calling Post id from Category. just cut it out (class Category), and paste it under class Post

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