Django - Create custom PrimaryKey with selected ForeignKey object - django

Problem:
I want to create a custom-PrimaryKey in ItemCode Model contain with selected-ForeignKey object. So, It's gonna change the custom-PrimaryKey every time submit a new ForeignKey field.
Here's my Model:
class ItemCategory(models.Model):
idItemCat = models.CharField(primary_key=True max_length=5)
nameCategory = models.CharField(max_length=150)
class ItemCode(models.Model):
idItemCode = models.CharField(primary_key=True, editable=False, max_length=20)
idItemCat = models.ForeignKey(ItemCategory, on_delete=models.DO_NOTHING)
To illustrate, here's the example of custom-PrimaryKey I wanna create: MN.202203.001
MN means Monitor from selected-ForeignKey object
Then, it change every time I submit new ForeignKey field, like this: CM.202203.002
CM means Camera from new selected-ForeignKey object
What I've tried:
I've tried to using request method but I don't know how to implemented it in my Model.
def CustomPK(request):
if request.method == 'POST':
category = ItemCategory.objects.get(pk=request.POST.get('idItemCat'))
return category
Question:
Is there anyway to get or fetch the object from selected-ForeignKey field to make a custom-PrimaryKey with request method? or is there any better way to do it?
If my question isn't clear enough, please let me know...

Related

populating a tuple with model objects

I have a simple checklist in my personal info form that users can fill. this checklist gets its choices from tuple and that tuple gets its items from another model called field like this:
class Field(models.Model):
id = models.AutoField(primary_key=True)
slug = models.CharField(max_length=16, default='default')
title = CharField(max_length=32)
INTERESTS = (Field.objects.values_list('slug', 'title'))
everything works just fine. however, when I add a new field object, INTERESTS tuple wont get updated without migrations. how can I update my tuple without any migrations? is it even possible?
this is my simplified models:
class PersonalInfo(models.Model):
interests = MultiSelectField(choices=INTERESTS, blank=True)
and my form:
class Interests(forms.ModelForm):
interests = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=INTERESTS)
class Meta:
model = PersonalInfo
fields = ['interests']
Not an actual answer, but it's too long for a comment. I dont know how much you "simplified the model", but you should change the interest into a ManyToManyField. Right now if any value will be deleted from Field, you will get invalid data in the database. If you will use ManyToManyField, it will it will make sure your DB data consistent will be consistent. So your model will look like this:
class PersonalInfo(models.Model):
interests = models.ManyToManyField(Field)
After doing this, using the ModelForm should handle the data in form for you without doing anything "manually" there.

ReverseManyToOne create object from children through django form

Using:
Python 3.7.3
django 2.2.5
mysql 5.7.27
I have the following models:
class Item(models.Model):
...
class Comments(models.Model):
Item = models.ForeignKey('Item', default=None, null=True, on_delete=models.CASCADE)
Comment = models.TextField(max_length=512, default="", blank=True)
I would like to create a Comments object, when creating the Item through a django form. I tried to do:
class ItemInsertForm(forms.ModelForm):
...
Comments = forms.CharField(required=False,
widget=forms.Textarea(attrs={'placeholder':"Use comments to describe item details \
or issues that other users should know",
'rows':5,
'cols':50,
}
)
)
def clean_Comments(self, *args, **kwargs):
_comment = self.cleaned_data.get('Comments')
_comments = Item.comments_set.create(Comment=_comment)
return _comments
but I get the following error:
'ReverseManyToOneDescriptor' object has no attribute 'create'
Both tables are empty, so no Item and no Comments currently exist. I guess that's why there is no 'create' method available. Is there a way I could achieve what I want?
Or is there another way to manage the comments for the Item object? I created another table to be able to associate multiple comments to the same item and differentiate between them. A character field in the Item class would concatenate all comments in a single string.
I see quite some issues with your code, but since I feel like you gave it an honest shot, I'll try to help you out as best as I can.
First of all your models.py file:
Model names should be singular, so instead of Comments, use Comment.
Class members should be lowercase, so Item and Comment should be changed to item and comment.
Comment.comment is still not very descriptive. The comment is the actual object, it's content is the text within the comment, so text would be more appropriate here.
A ForeignKey with null=True already sets default to None.
Taking this into account and cleaning up your models.py:
class Item(models.Model):
...
class Comment(models.Model):
item = models.ForeignKey(Item, null=True, on_delete=models.CASCADE)
text = models.TextField(max_length=512, default="", blank=True)
Then, moving on to your form:
Since it's a form for creation Comments, a more appropriate name would be CommentForm.
def clean_Comments(self, *args, **kwargs): is a function reserved for doing validation on the Comments field, not for creating an object from the form input. For that you can use the ModelForm's save() method. You only need to define a save method if you're going to perform some custom logic though.
Let's fix those issues first, before I move onto the error message your getting:
class ItemInsertForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text']
text = forms.CharField(required=False,
widget=forms.Textarea(attrs={'placeholder':"Write your comment to describe item details \
or issues that other users should know",
'rows':5,
'cols':50,
}
)
)
This form, when submitted, will create a Comment object. However, there is still no ability to add the comment to an Item.
To do this, you need to make sure there are Item instances in the database, or allow the user to create one through an ItemForm
There are multiple ways to do this:
Add a ModelChoiceField to the CommentForm, which will allow the user to select an item from a select.
item = forms.ModelChoiceField(queryset=Item.object.all(),
to_field_name = '<item_name>',
empty_label="Select an Item")
When you want to add this form to an something like an ItemDetailPage, you can use the currently viewed Item using something like
item = Item.objects.get(pk=<item_id>)
or
item = Item.objects.create(<item_properties_here>)
then, when saving your form:
comment = form.save()
comment.item = item.
comment.save()
The third way is what you were trying, and why you were getting an error. Retrieve an item, then add the comment saved from the form to the item.comment_set.
Something like this:
item = Item.objects.get(pk=<item_id>)
comment = form.save()
item.comments_set.add(comment)
item.save()

Update multiple fields of member of an instance simultaneously

Suppose I have a User model and this model
class modelEmployer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
employer_image = models.ImageField(upload_to='images/', default='')
Now suppose i have an instance of modelEmployer and I would like to update the content of the user object in it. I know I can do this
instance.user.email = new value
instance.first_name = new value
instance.save()
I read we can run an update on a queryset (even if it returns one object). Now suppose I have a dictionary like this
dict = {"first_name : "John","last_name" : "deer",....}
How can i do something like this
modelEmployer.object.filter(instance.user.email=dict["email"]).update(only update the user objects as I would like to update the user object of this field using directly the dictionary. Any suggestions ?
You can use explicitly mention the relation and do it,
dict = {"user__first_name" : "John","user__last_name" : "deer",....}
And in the ORM, do as
modelEmployer.object.filter(instance.user.email=dict["email"]).update(**dict)
Hope this will solve your issue

django model field like view

I'd like to have a model field that will return the latest related of another model.
An example-
class Thing(models.Model):
name = models.CharField(max_length=200)
state = models.ForeignKey(State, query=latest) #pure fantasy
class State(models.Model):
change = models.DateTimeField(auto_now_add=True)
thing = models.ForeignKey(Thing)
Assume that the model class State has a many to one relationship to Thing.
given- some_thing = Thing.object.all()[0]
I want some_thing.state to be the instance of State that has the most recent State.change value for the instance Thing that I have in hand.
I'd like to specify at the Django Model level an instance variable that does what I've described above. I can think of two ways to do this, but neither is at this level:
at the actual DB level -- create a view and turn off django db
syncing
(http://stackoverflow.com/questions/507795/can-i-use-a-database-view-as-a-model-in-django)
the view level -- when I create new State row manually set that row to the related Thing.state instance.
You cannot have a database level dynamic foreign key. You can, however, have a property or a method that captures your item for you:
class Thing(models.Model):
name = models.CharField(max_length=200)
#property
def state(self):
return State.objects.latest('change')
class State(models.Model):
change = models.DateTimeField(auto_now_add=True)
thing = models.ForeignKey(Thing)

Django Models Manager for saving custom processed data in a field

A noob here. I have a model class where I want to save something processed in one of the fields of that table. am trying to use a ModelManager for that but do not know if it is possible or how to.
I want to save a custom url for each post here. So I want to have a method in PostManager class which will calculate hash of something (say current time) and save it as a url. I could not find any syntax help so asking it here.
class Post (models.Model):
name = models.CharField(max_length=1000, help_text="required, name of the post")
description = models.TextField(blank=True)
created_datetime = models.DateTimeField(auto_now_add=True, editable=False)
modified_datetime = models.DateTimeField(auto_now=True, editable=False)
custom_hashed_url = models.CharField(unique=True, max_length=1000, editable=False)
def save(self, *args, **kwargs):
#How to refer to the custom_hashed_url in the Post class?
super(Model, self).save()
If you want the url to be saved in the database with the rest of the information, it will need to appear in the model as a field.
Change the url to an appropriate field type and set its 'editable' attribute to False, as you've done with the datetime fields. This will stop it appearing in forms.
You could then override the model's save method (see Django docs) so that it calculates the post's url and adds it automatically as the instance is saved!
Model managers are used for 'model level' interactions that work with many instances, or sets of instances. In this case you are trying to manipulate a single instance. We use a field to store the information in the database for the record and a method (in this case overriding a built-in method to hook into the default behaviours) to calculate the field's value.
Good luck!