Set a field value within form __init__ function - django

I am trying to find out an efficient way to set a field value within form init method. My models are similar to below
class Users(models.Model):
firstname = models.CharField()
lastname = models.CharField()
class profile(models.model):
user = models.ForeignKey(Users, on_delete=models.PROTECT)
class logindetails(models.model):
user = models.ForeignKey(Users, on_delete=models.PROTECT)
profile = models.ForeignKey(profile, on_delete=models.PROTECT)
login_time = models.DateField(auto_now=True)
My form is like as below:
class LoginForm(forms.ModelForm):
class Meta:
model = logindetails
fields = [__all__]
def __init__(self, *args, **kwargs):
self._rowid = kwargs.pop('rowid', None)
super(LoginForm, self).__init__(*args, **kwargs)
instance = profile.objects.get(id=self._rowid)
self.fields['user'] = instance.user <--- Facing difficulties here
Any help will be appreciated.

Django had built-in ways of setting initial form values, the documentation is available here: https://docs.djangoproject.com/en/3.0/ref/forms/api/#dynamic-initial-values

Related

Cannot set values on a ManyToManyField which specifies an intermediary model

How can I set values on to a ManyToManyField which specifies an intermediary model?
In the models.py
class BookUser(models.Model):
email = models.EmailField()
class Book(models.Model):
author_id= models.CharField(max_length=255)
send_to = models.ManyToManyField(BookUser, through='BookUserRelationship')
book_id = models.AutoField(primary_key=True)
file_size = models.CharField(null=True)
class BookUserRelationship(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
user = models.ForeignKey(BookUser, on_delete=models.CASCADE)
shared_date = models.DateTimeField(auto_now_add=True,null=True,blank=True)
Tried to update in serializers.py
class BookSerializer(serializers.ModelSerializer):
send_to = BookUserSerializer(many=True, read_only=True)
class Meta():
model = Book
fields = ('book_id', 'author_id','file_size','send_to')
class BookUserSerializer(serializers.ModelSerializer):
model = BookUser
fields = ('email')
In the views.py for listing the books by passing the book_id as query params
class BookListView(generics.ListCreateAPIView):
serializer_class = serializers.BookSerializer
def get(self, request, *args, **kwargs):
user = self.request.user
book_id = self.request.query_params.get('book_id', None)
if book_id:
book = models.Book.objects.filter(book_id=book_id)
return Response(serializers.BookSerializer(book[0]).data)
You don't need to do anything at all. You have already set the relevant data in your for loop, by creating the BookUserRelationship instances. That is the many-to-many relationship; you should just remove the instance.send_to.set(emails) line.

Issue when looping through form fields in Django's __init__ method

My goal is to loop through all form fields and to assign certain classes to them like this:
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'form-control input-sm plain'
if field.required == True:
field.widget.attrs['required'] = ''
class Meta:
model = Contact
fields = '__all__'
The issue with this code is that self.fields.items() seems to be empty (and as a result I never get into the for-loop).
My guess is that the issue arose either because of my upgrade from Django 1.9 and python 2 to Django 1.10 and python 3, or because of custom manager present in the definition of the underlying model.
Could anyone share expertise on this?
class Contact(BaseMixin, DeleteMixin):
provider_account = models.ForeignKey(ProviderAccount, models.DO_NOTHING)
client_id = models.IntegerField()
name = models.CharField(max_length=300)
profile_photo_url = models.CharField(max_length=100, default = 'no_image.jpg')
event_type_id = models.IntegerField(EventType.choices(), blank=True, null=True)
is_satisfied = models.NullBooleanField()
objects = CustomQuerySetManager()
class Meta:
managed = False
db_table = 'contact'
class QuerySet(QuerySet):
#....
Your form is a standard form, not a model form; the Meta class is ignored and the only fields are those you define yourself.
Your form should inherit from forms.ModelForm for this to work.

rendering foreign field in django form

I have a model where a field references a foreign key from another model as:
class DummyModel(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=150)
image_type = models.ForeignKey(ImageTypeModel) # Foreign key
class Meta:
db_table = "dummy"
The parent model is also simple:
class ImageTypeModel(models.Model):
name = models.CharField(max_length=100)
dims = models.IntegerField()
class Meta:
db_table = "imagetypes"
Now, I attempt to render a record in a form and for that purpose I am using django-crispy-forms. So, I have:
class DummyForm(ModelForm):
class Meta:
model = DummyModel
fields = ['name', 'description', 'image_type']
def __init__(self, *args, **kwargs):
super(DummyForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-sm-2'
self.helper.field_class = 'col-sm-10'
#self.helper.form_tag = False
self.helper.layout = Layout(
Field('name'),
Field('description'),
Field('image_type'))
The image_type field renders as a drop-down list which is perfect but instead of the name of the image types, the entries are all labelled ImageTypeModel. Is there a mechanism so that I can display the corresponding name from the ImageTypeModel record but when the form is saved it saves the primary key rather than the name.
You should implement the __unicode__ (python 2) or __str__ (python 3) method inside the model.
Like this:
class ImageTypeModel(models.Model):
name = models.CharField(max_length=100)
dims = models.IntegerField()
class Meta:
db_table = "imagetypes"
# For Python 2
def __unicode__(self):
return self.name
# For Python 3
def __str__(self):
return self.name

Django model id turns into a tuple

I have a super class for my models as below:
class BaseModel(models.Model):
""" BaseClass vase aksare model ha """
def __init__(self, *args, **kwargs):
super(BaseModel, self).__init__(args, kwargs)
print('******> base model __init__')
status = models.IntegerField(default=1)
is_deleted = models.BooleanField(default=False)
create_user = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_creator_related")
create_date = models.DateTimeField()
update_date = models.DateTimeField()
update_user = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_updater_related")
class Meta:
abstract = True
def validate(self):
print('^^^^^^^^^^^^^^^^^^^^^^^^^^^^base validation')
and I have a profile model as below:
class Profile(BaseModel):
def __init__(self, *args, **kwargs):
super(Profile, self).__init__(args, kwargs)
""" User profile """
user = models.OneToOneField(User, related_name='profile')
mobile = models.CharField(max_length=25, null=True)
firstname_en = models.CharField(max_length=500, null=True)
lastname_en = models.CharField(max_length=500, null=True)
gender = models.IntegerField(default=0)
birth_date = models.DateTimeField(null=True)
edu_bg = models.ForeignKey('Category', related_name="profile__edu_bg", null=True)
region = models.ForeignKey('Category', related_name="profile__region", null=True)
credit = models.DecimalField(default=0, decimal_places=6, max_digits=15)
key = models.TextField(null=True)
secret = models.TextField(null=True)
I have an error when I want to insert a new userProfile as below:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'.
then print the vars(userprofileObject) and realized that 'id': ((), {}), however, I have not set it. When I removed the __init__ functions or set id to None in insertion code, problem solved.
Any idea?
I need those __init__ and also don't want to set id=None in my code
This is how django's models work. You shouldn't change their __init__ method.
This is why
You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved. Rather than overriding __init__, try using one of these approaches:
# Add a classmethod on the model class:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
#classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
Source https://docs.djangoproject.com/en/1.10/ref/models/instances/#django.db.models.Model
Also read this Writing a __init__ function to be used in django model

django model forms filter queryset

I have the following model:
class Article(models.Model):
title = models.CharField()
description = models.TextField()
author = models.ForeignKey(User)
class Rating(models.Model):
value = models.IntegerField(choices=RATING_CHOICES)
additional_note = models.TextField(null=True, blank=True)
from_user = models.ForeignKey(User, related_name='from_user')
to_user = models.ForeignKey(User, related_name='to_user')
rated_article = models.ForeignKey(Article, null=True, blank=True)
dtobject = models.DateTimeField(auto_now_add=True)
Based upon the above model, i have created a model form, as follows:
Model Forms:
class RatingForm(ModelForm):
class Meta:
model = Rating
exclude = ('from_user', 'dtobject')
Excluding from_user because the request.user is the from_user.
The form renders well, but in to_user in the dropdown field, the author can rate himself as well. So i would want the current_user's name to populate in the dropdown field. How do i do it?
Override __init__ to remove current user from the to_user choices.
Update: More Explanation
ForeignKey uses ModelChoiceField whose choices are queryset. So in __init__ you have to remove the current user from to_user's queryset.
Update 2: Example
class RatingForm(ModelForm):
def __init__(self, current_user, *args, **kwargs):
super(RatingForm, self).__init__(*args, **kwargs)
self.fields['to_user'].queryset = self.fields['to_user'].queryset.exclude(id=current_user.id)
class Meta:
model = Rating
exclude = ('from_user', 'dtobject')
Now in the view where you create RatingForm object pass request.user as keyword argument current_user like this.
form = RatingForm(current_user=request.user)