Django - how to access a ForeignKey parent's attribute? - django

I'm a newbie in Django, and I don't know how to this.
I have a model 'Seller':
class Seller(models.Model):
seller_name = models.CharField(max_length=50)
def __str__(self):
return self.seller_name
and a model 'Item':
class Item(models.Model):
seller = models.ForeignKey(Seller, on_delete=models.CASCADE)
item_name = models.CharField(max_length=100)
item_category = models.CharField(max_length=100, choices=ALL_CATEGORIES)
item_price = models.FloatField()
item_preview = models.ImageField(upload_to='previews/<the seller's name>')
def __str__(self):
return self.item_name
connected via ForeignKey to Seller.
In this model, I have an ImageField, and I want it to upload the files to previews/Seller's name directory, but I don't know how to access the Seller's name from Item. Is it possible? Or am I doing something I am not supposed to? Because I couldn't find any similar cases in the internet.

You can access Seller name like this.
item = Item.objects.get(<condition>)
item.seller.seller_name
If you are using filter
items = Item.objects.filter(<condition>)
items[0].seller.seller_name #You need to provide index in queryset
or
for item in items:
item.seller.seller_name
you can't provide a path like that. You can either use a callable in upload_to or can use the lambda function.
item_preview = models.ImageField(upload_to=lambda instance: 'previews/{0}'.format(instance.seller.seller_name))
If you use upload_to callable
item_preview = models.ImageField(upload_to=upload_file_handler)
def upload_file_handler(instance, filename):
return 'previews/{0}'.format(instance.seller.seller_name)

Related

Need to Fetch specific foreign key object product from database in Django

Hi everyone I am new at Django and working on e-commerce site. I create a model name category and pass it to model shop by using foreign key. In Category model I have category Sale and i want to fetch all products that have category sale in my landing page and rest of us in shop page. Any one please help me how I do it?
My model.py code is:
class category(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class shop(models.Model):
s_id = models.AutoField(primary_key=True)
s_name = models.CharField(max_length=50)
s_category = models.ForeignKey(category, on_delete= models.CASCADE)
s_artical_no = models.IntegerField(default=0)
View.py:
def index(request):
prod = shop.objects.get(s_category = 4)
params = {'prod': prod}
return render(request, "main/index.html", params )
Use related_name to accomplish this
class shop(models.Model):
s_category = models.ForeignKey(category, on_delete= models.CASCADE, related_name='shop_list')
In views.py
def index(request):
specific_category = category.objects.get(id=4)
prod = category.shop_list.all() #use related_name here
params = {'prod': prod}
return render(request, "main/index.html", params )
Hint: your classes names should follow the UpperCaseCamelCase convention so it should be Shop, Category
s_category is a category instance, you can't pass a category id. First get the category object for "Sale" i.e.
sale_category = category.objects.get(pk=4)
then simply use
prod = sale_category.shop_set.all()
As a side note, try to use PEP-8 compliant class names. The way you name your classes is confusing

Syntax to reverse-query a cached queryset

I have the following 3 models related by Foreign Key as following:
class Seller(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Genre(models.Model):
seller= models.ForeignKey(Seller, related_name="genre", on_delete=models.CASCADE)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Book(models.Model):
genre= models.ForeignKey(Genre, related_name="book", on_delete=models.CASCADE)
name = models.CharField(max_length=20)
def __str__(self):
return self.name
And I want to retrieve the whole 3 tables in one database query, by querying the Seller objects, as following:
sellers = Seller.objects.select_related('genre', 'book').all().values('name')
seller_df = pd.DataFrame(list(sellers))
What is the syntax to filter for books carried by a particular seller, without hitting the database again (by utilizing either the Seller queryset or the pandas seller_df)
seller1 = seller_df ['name'].iloc[0]
seller1_books = Book.objects.filter(...)
seller_last = seller_df ['name'].iloc[-1]
seller_last_books = Book.objects.filter(...)
I dont know so mach about caching but I know something that you like:
We use select_related when the object is single like onetoone or fk.
.
for many to many or reverse fk like your example use prefetch_related

In Django REST framework, how do you access a field in a table referenced by a foreign key

I have the following models in Django:
class campaign(models.Model):
start_date = models.DateField('Start Date')
end_date = models.DateField('End Date')
description = models.CharField(max_length=500)
name = models.CharField(max_length=200)
active_start_time = models.TimeField()
active_end_time = models.TimeField()
last_updated = models.DateTimeField('Date updated',auto_now=True)
active = models.BooleanField(default=True)
client_id = models.ForeignKey('client',on_delete=models.PROTECT)
def __unicode__(self):
return u'%d | %s | %s' % (self.id,self.name, self.description)
class campaign_product(models.Model):
product_id = models.ForeignKey('product',on_delete=models.PROTECT)
last_updated = models.DateTimeField('Date updated',auto_now=True)
campaign_id = models.ForeignKey('campaign',on_delete=models.PROTECT)
class product(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=500)
sku = models.CharField(max_length=200,blank=True,null=True)
retail_price = models.DecimalField(decimal_places=2,max_digits=11)
discount_price = ((1,'Yes'),(0,'No'))
discounted_price = models.DecimalField(decimal_places=2,max_digits=11,blank=True,null=True)
category_id = models.ForeignKey('category',on_delete=models.PROTECT)
last_updated = models.DateTimeField('Date updated',auto_now=True)
active = models.BooleanField(default=True)
def __unicode__(self):
return u'%d | %s' % (self.id, self.name)
I also have the following serializer:
class campaignProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = campaign_product
fields = ('product_id', 'campaign_id')
And the following view set behavior in the urls.py file:
class campaignProductViewSet(viewsets.ModelViewSet):
queryset = campaign_product.objects.filter(campaign_id__start_date__lte=datetime.now(),campaign_id__end_date__gte=datetime.now(),campaign_id__active__exact=True)
serializer_class = campaignProductSerializer
My problem is I need to include the name field from the products model in my query results when for instance a request is made on http://127.0.0.1:8000/campaign_product/1/. Currenly this request returns only the product_id and the campaign_id. I tried making the serializer as follows:
class campaignProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = campaign_product
fields = ('product_id', 'campaign_id', 'product.name')
But then the service returns the following error:
Field name `product.name` is not valid for model `campaign_product`.
I event tried using product__name with and without quotes. Without quotes it tells me that there is no such variable, and with quotes it gives the is not valid for model error similar to the above. Heeelp! Getting this extra field is proving to be a pain :-(
What you want will need to look something more like this:
class campaignProductSerializer(serializers.HyperlinkedModelSerializer):
product_name = serializers.CharField(source='product_id.name')
class Meta:
model = campaign_product
fields = ('product_id', 'campaign_id', 'product_name')
P.S. As an unrelated side note, it is generally a convention in Python code to name classes with CamelCase, such as Campaign, CampaignProduct, Product, and CampaignProductSerializer.
Edit: P.P.S. Originally, I had put written the product_name field with source='product.name'. This was actually due to me looking at the code too quickly and making assumptions based on Django conventions. Typically, with a Django ForeignKey, you would name the ForeignKey field after the model you are linking to, rather than explicitly naming it with _id. For example, the CampaignProduct model would typically be written with product = ForeignKey(...) and campaign = ForeignKey(...). In the background, Django will actually use product_id and campaign_id as the database field names. You also have access to those names on your model instances. But the product and campaign variables on your model instances actually return the objects which you are referring to. Hopefully that all makes sense.

restframework show objects in html but not id

Rest-framework support post data in the web.
But about ForeignKey,it shows just the same "Objects" without feature to make sure which is what I want.
this is my code:
server models:
node = models.ForeignKey(
Node,
related_name='server',
null=True,
)
serializers:
class ServerSerializer(serializers.ModelSerializer):
class Meta:
model = Server
fields = ( 'node')
How can I get the server objects' feature instead of "Server Object"?
You should write a __unicode__() method for your model to have more readable representation. Assuming your model has a field name which contains the name of the object, do something like:
class Server(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
In Case you are using Django with Python3 you should use instead the str():
class Server(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name

Correct way of getting count on FK

What is the correct way of getting the 'contact' count from within my 'Group'?
I was thinking of just creating a new method within 'group' and filter(), but this means hitting the db again which seems bad, right?
class GroupManager(models.Manager):
def for_user(self, user):
return self.get_query_set().filter(user=user,)
class Group(models.Model):
name = models.CharField(max_length=60)
modified = models.DateTimeField(null=True, auto_now=True,)
#FK
user = models.ForeignKey(User, related_name="user")
objects = GroupManager()
def get_absolute_url(self):
return reverse('contacts.views.group', args=[str(self.id)])
class Contact(models.Model):
first_name = models.CharField(max_length=60)
last_name = models.CharField(max_length=60)
#FK
group = models.ForeignKey(Group)
group_object.contact_set.count() should do it. Django creates the relation by adding _set to the end of the foreign key's model name.
Have a look at the docs on related objects for more info.