Here's my code:
class Publisher(models.Model):
name = models.CharField(
max_length = 200,
unique = True,
)
url = models.URLField()
def __unicode__(self):
return self.name
def save(self):
pass
class Item(models.Model):
publisher = models.ForeignKey(Publisher)
name = models.CharField(
max_length = 200,
)
code = models.CharField(
max_length = 10,
)
def __unicode__(self):
return self.name
I want to be able to access each Item from the Publisher save function. How can I do this?
For instance, I'd like to append text to the code field of each Item associated with this Publisher on the save of Publisher.
edit:
When I try to implement the first solution, I get the error "'Publisher' object has no attribute 'item_set'". Apparently I can't access it that way. Any other clues?
edit 2:
I discovered that the problem occurring is that when I create a new Publisher object, I add Items inline. Therefor, when trying to save a Publisher and access the Items, they don't exist.
Is there any way around this?!
You should be able to do something like the following:
def save(self, **kwargs):
super(Publisher, self).save(**kwargs)
for item in self.item_set.all():
item.code = "%s - whatever" % item.code
I don't really like what you're doing here, this isn't a good way to relate Item to Publisher. What is it you're after in the end?
Related
I was trying to make it this way but instead of {{product.id}}, folder is named None.
I read some articles about that, and I found out that is because folder is being made before whole object. So how should I do that to make it work?
models.py:
def getImageURL(self, filename):
return "products_images/" + str(self.pk) + "/product_image.png"
class Product(models.Model):
name = models.CharField(max_length=200)
image = models.ImageField(upload_to=getImageURL, default="media/static/products_images/default.png" )
changed my funtion to:
def getImageURL(instance, filename):
return "products_images/{}/product_image.png".format(instance.id)
But it works only while edditing existing object. When I'm trying to make a new one id is set to None.
Edit:
ok, finally I did it this way:
def getFileNumber():
queryset = Product.objects.all().order_by('pk')
last = queryset.last()
last_id = last.id
file_number = last_id+1
return str(file_number)
def getImageURL(instance, filename):
return "products_images/{}/product_image.png".format(getFileNumber())
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
availability = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=2)
Probably it is not the best way to do that but it's very simple to understand so why not to use it.
Some debugging:
def getFileNumber():
queryset = Product.objects.all().order_by('pk')
if queryset:
last = queryset.last()
last_id = last.id
file_number = last_id+1
return str(file_number)
else:
file_number=1
return str(file_number)
def getImageURL(instance, filename):
path = os.path.join("products_images/{}/product_image.png".format(getFileNumber()))
print(path)
if os.path.isfile("media/" + path):
print("image with this id already exist, ")
os.remove("media/" + path)
return path
else:
return path
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
availability = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=2)
The following is the issue:
The instance doesn't have a primary key yet before it is created
When the instance gets saved in the database, then you can get the primary key
Maybe use signals, somehow? Do the logic it in the view after saving it?
Alternative option to pk:
You can generate a UUID for the object.
id = models.UUIDField(
primary_key = True,
default = uuid.uuid4,
editable = False)
Or alternatively:
Have a look at this package, you can set the uuid alphabet, length, and some more. This would allow you access to the id, for sure (same with uuid).
https://pypi.org/project/shortuuid/
id = ShortUUIDField(
length=16,
max_length=40,
prefix="id_",
alphabet="abcdefg1234",
primary_key=True,
)
Sidenote:
def getImageURL(self, filename): #Self would normally be defined as instance, but I suppose this is just semantics.
This is because the id is saved to the model after calling save(). The first guess would be to use save() to get the object in return. But save() does not return anything. So I put together a little example
class Thingy(models.Model):
name = models.CharField(
_('name'),
max_length=64,
)
def save(self, *args, **kwargs):
super(Thingy, self).save(*args, **kwargs)
print(self.pk)
My test was:
>>> t = Thingy(name="lol")
>>> t.save()
1
And it printed the primary key since save() mutades self. You could check if the pk exists before save(). If yes, just add the image path. If not. Execute save() first, manipulate the image path using pk, and save the object again. It is not elegant in any way, but I guess that is the only way.
I might be confused however when I check the django-admin panel I can see (will provide a screenshot) , over 50 models attached to my primary model, however whenever I make a query in the code and try to access the set associated with the field I only ever get one entry. I am trying to make one query and check all models associated with the field.
My models.py code:
class TokenData(models.Model):
name = models.CharField(max_length=200)
contract_address = models.CharField(max_length=200,primary_key=True, unique=True)
def save(self, *args, **kwargs):
#print('save() is called.')
super(TokenData, self).save(*args, **kwargs)
def __str__(self):
return self.name
class WalletData(models.Model):
address = models.CharField(max_length=200,primary_key=True,unique=True)
contract_address = models.ForeignKey(to=TokenData,on_delete=models.CASCADE,)
last_bitquery_scan = models.CharField(max_length=200)
def __str__(self):
return self.address
I am trying to access the model like so :
WalletData.objects.filter(address=address)
One thing I noticed is when I create a variable containing the filter, and access the contract_address in the WalletData model, I can endlessly query myself in a circle for lack of a better word, by accessing the set and executing a get against it.
I am just wanting to access all 50 models like shown below
The 50+ objects you see in the drop down are just all the TokenData objects in the DB listed by the name.
From what i can understand what you want is all the TokenData associated with a particular WalletData address, if so then for a WalletData object w you can do
TokenData.objects.filter(contact_address = w.contact_address).values_list('name',flat=True)
This gives you all the TokenData name associated to a WalletData address.
I ended up figuring it out here was my fix:
Models.py
class TokenData(models.Model):
name = models.CharField(max_length=200)
contract_address = models.CharField(max_length=200,primary_key=True, unique=True)
def save(self, *args, **kwargs):
#print('save() is called.')
super(TokenData, self).save(*args, **kwargs)
def __str__(self):
return self.name
class WalletData(models.Model):
address = models.CharField(max_length=200,primary_key=True,unique=True)
#contract_address = models.ForeignKey(to=TokenData,on_delete=models.CASCADE,)
last_bitquery_scan = models.CharField(max_length=200)
def __str__(self):
return self.address
class WalletHolding(models.Model):
token = models.ForeignKey(to=TokenData,on_delete=CASCADE)
wallet = models.ForeignKey(to=WalletData,on_delete=CASCADE)
def __str__(self):
return self.token
I had to add another model i.e WalletHolding, this way when I query the WalletHolding by the wallet field I get all tokens associated with the wallet using a query like this:
WalletHolding.objects.filter(wallet=address).values_list('token',flat=True)
Result:
I have two tables, which are connected with each other through a cross table. (Recipes <--> Ingredients)
My Serializer works ok, I can send POST-Requests and it saves everything. The problem ist, that every time a new Recipe comes in with let just say the Ingredient "Milk" then my Serializer creates a new entry in my database named Milk, although I have an already existing entry "Milk" in my database.
How do I tell my Serializer to use the Id of an already existing entry instead of creating a new one every time for the cross table.
Here is how I thought I could fix it, but it clearly doesn't:
class RecipeIngredientSerializer(serializers.ModelSerializer):
ingredient = IngerdientSerializer()
class Meta:
model = recipe_ingredients
fields = ['amount', 'unit', 'ingredient']
def create(self, validated_data):
ingredient_validated_data = validated_data.pop('ingredient')
ingredient_serializer = self.fields['ingredient']
ingredientDict = dict(ingredient_validated_data)
// This is where I try to check if there is already an ingredient with the name from the form
ingredientObj = ingredient.objects.all().filter(ingredient_name=ingredientDict['ingredient_name']).
if not ingredientObj:
ingredient_instance = ingredient.objects.create(**ingredientDict)
validated_data['ingredient'] = ingredient_instance
else:
ingredient_instance = ingredient_serializer.create(ingredientDict)
validated_data['ingredient'] = ingredient_instance
recipe_ingredients_instance = recipe_ingredients.objects.create(**validated_data)
return recipe_ingredients_instance
This code also seems to work, at least I find an existing ingredient, but after the last create() it seems to ignore what ever I push into the validated_data['ingredient'] object.
EDIT
my models are:
class recipe_ingredients(models.Model):
recipe = models.ForeignKey(recipe, models.CASCADE)
ingredient = models.ForeignKey(ingredient, models.CASCADE)
amount = models.IntegerField(default=0)
unit = models.CharField(max_length=50)
def __str__(self):
return self.ingredient.ingredient_name + ' of Recipe: ' + self.recipe.recipe_name
class recipe(models.Model):
recipe_name = models.CharField(max_length=200)
assembly_time = models.IntegerField(default=0)
number_of_servings = models.IntegerField(default=0)
tags = models.ManyToManyField(tag, blank=True)
def __str__(self):
return self.recipe_name
class ingredient(models.Model):
ingredient_name = models.CharField(max_length=200)
ingredient_calories = models.IntegerField('Calories per 100 Units', default=-1)
default_unit = models.CharField(max_length=50)
def __str__(self):
return self.ingredient_name
I got the answer, finally. My mistake is this line in my Serializer:
ingredientObj = ingredient.objects.all().filter(ingredient_name=ingredientDict['ingredient_name']).
if not ingredientObj:
ingredient_instance = ingredient.objects.create(**ingredientDict)
validated_data['ingredient'] = ingredient_instance
I changed it now so that it looks something like this:
ingredientObj = ingredient.objects.all().filter(ingredient_name=ingredientDict['ingredient_name']).
if len(ingredientObj):
ingredient_instance = ingredientObj.first()
validated_data['ingredient'] = ingredient_instance
The ingredient.object.create(**ingredientDict) does actually create a new object (who would have known ;) ). This is probably still an ugly solution and I am open to more criticism but this does work for now.
My question is how i can insert multiple keywords in one django field and show them in a template like stackoverflow tags.
Models:
class Jobs(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(blank=True, default='')
company = models.ForeignKey(Company, on_delete=models.CASCADE)
tags = ?????
Create another class and use many-to-many relationship between jobs class (tags) and new class:
class Tags(models.Model):
tag_name=models.CharField()
In jobs class
tags=models.ManyToManyField(Tags)
For show in template you can use for loop, etc.
Make it a Comma separated value.
class Jobs(models.Model):
tags = models.TextField()
def tag_list(self):
return self.tags.split(",")
def add_tag(self, tag_str):
current_tags = self.tag_list()
current_tags.append(tag_str)
current_tags = set(current_tags)
new_tag_string = ",".join(current_tags)
self.tags = new_tag_string
# you could save the model now or let caller save it outside of this method. I suggest letting caller save the model.
def remove_tag(self, tag_str):
current_tags = self.tag_list()
current_tags.remove(tag_str)
new_tag_string = ",".join(current_tags)
self.tags = new_tag_string
# you could save the model now or let caller save it outside of this method. I suggest letting caller save the model.
I would like to create a function in views.py to retrieve an information from this class:
class Vin(models.Model):
def __unicode__ (self):
return self.nom
name = models.CharField( max_length = 30)
year = models.CharField (max_length = 4)
appellation = models.ForeignKey(Appellation)
photo = models.CharField (max_length = 70)
quantity = models.IntegerField ()
released = models.IntegerField()
and retrieve it by its attribute "name".
So for instance, if i have a Wine ("chardonnay", 1990, ...) only retrieve chardonnay.
Thanks !
Your view function will be called after the user enters a URL that is in your urls.py. The url entered may provide you with the additional information you need to query the database and get information on the Vin object you need.
If you want a view to just return every Vin in your database. Something like this might be helpful for you:
def get_vins(request, *args, **kwargs):
vins = Vin.objects.all().values_list('name', flat=True)
return render(request, 'somepage.html', {"vins": vins})
Your question is really vauge and you should read the django documentation. This is a very basic question that all starters should learn.