In my models I have:
class Collaborator(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(verbose_name= 'fotografia', upload_to='collaborators')
According to Django Docs this is the correct way to extend a user object, but I couldn't find a reference on how to name this "collaborator" after the user.
I'm referring to the Django Admin Interface where creating a Collaborator will result in a object named "Collaborator object". Is there any way for the Collaborator to appear with the user's name?
You need to define a __str__ method, like explained in Models Docs:
class Collaborator(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(verbose_name= 'fotografia', upload_to='collaborators')
def __str__(self):
return self.user.first_name #or whatever else you want.
Related
Basically, I am working on a django project, and whenever I insert data into the database, the result is weirdly formatted.
this is my model
customer.py
class Customer(models.Model):
user = models.OneToOneField(User,null=True,blank=True,on_delete=models.CASCADE)
name = models.CharField(max_length=200, null=True)
email= models.CharField(max_length=200, null=True)
phone_number= models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
Now, say I have saved a new customer
new_customer = Customer.objects.create(name="Henry",email="henry#mail.com",phone_number="+330145786259")
new_customer.save()
when i try to retrieve the customer name i get this:
print(new_customer.name)
>('henry',)
Anyone has any insight for me???
I tried to recreate the model on a new project but still having the same result
In your customer class, you have defined a 1:1 relationship with the in-built user model class of django. And when you are creating the customer object, new_customer, you have not specified the 'user' attribute; hence, your customer object is missing a key element.
The user object already has an in-built field for storing names. It is 'first_name' and 'last_name.' You need to create a user model first before being able to create your 'Customer' model.
Your models.py should look something like this:
from django.contrib.auth.models import User
class Customer(models.Model):
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
phone_number= models.CharField(max_length=200, null=True)
def __str__(self):
return self.user.first_name
# to return email -> self.user.email
Now to create a 'Customer' object in view.py:
from django.contrib.auth.models import User
from .models import Customer
# create a user object
myuser = User.objects.create_user(username='john', email='jlennon#beatles.com', password='glass onion')
# pass the user object to the customer model
mycustomer = Customer.objects.create(user=myuser, phone_number=123456789)
# save the customer object
mycustomer.save()
Explore django ModelForms to define the user model as per your specifications, e.g, if you don't require your users to have passwords associated with them, etc.
After much testing, I realized why I was getting the weird output.
I was directly passing data from a form to the object creation method, like so:
data = json.loads(request.body)
new_customer = Customer.objects.create(name=data['name'],email="henry#mail.com",phone_number="+330145786259")
new_customer.save()
So assigning the received data to a variable before passing it to the object creation method seems to be the right way of doing things... At least, it is working for me.
This question already has answers here:
What is the difference between __str__ and __repr__?
(28 answers)
Closed last month.
I'm reading and trying to understand django documentation so I have a logical question.
There is my models.py file:
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=255)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=255)
email = models.EmailField()
def __str__(self):
return self.name
class Post(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
What is doing here each __str__ function in each class?
What is the reason I need those functions in it?
You created a Blog model. Once you migrate this, Django will create a table with "name" and "tagline" columns in your database.
If you want to interact with the database with the model, for example create an instance of the model and save it or retrieve the model from db,
def __str__(self):
return self.name
will come handy. Open the python interactive shell in your project's root folder via:
python manage.py shell
Then
from projectName.models import Blog
Blog.objects.all() # will get you all the objects in "Blog" table
Also, when you look at the models in your admin panel, you will see your objects listed, with the name property.
The problem is, the return will look like this if you did not add that function:
<QuerySet [<Blog:>,<Blog:>,<Blog:>....]
So you will not know what those objects are. A better way to recognize those objects is retrieving them by one of its properties which you set it as name. This way you will get the result as follow:
<QuerySet [<Blog:itsName>,<Blog:itsName>,<Blog:itsName>....]
If you want to test this out, run python manage.py shell and run:
from projectName.models import Blog
# The below will create and save an instance.
# It is a single step. Copy-paste multiple times.
Blog.objects.create(name="first",tagline="anything")
Blog.objects.all() # check out the result
The __str__ method just tells Django what to print when it needs to print out an instance of the any model. It is also what lets your admin panel, go from this
Note: how objects are just plainly numbered
to this
.
Note: proper object names here
You could choose what to show in the admin panel, as per your choice. Be it a field value or a default value or something else.
This overrides the default name of the objects of this class, it's something like Author:object which isn't very helpful.
overriding it gives a more human friendly name of the object like the Author.name
def str(self): is a python method which is called when we use print/str to convert object into a string. It is predefined , however can be customised. Will see step by step.Suppose below is our code.
class topics():
def __init__(self,topics):
print "inside init"
self.topics=topics
my_top = topics("News")
print(my_top)
Output:
inside init
<__main__.topics instance at 0x0000000006483AC8>
So while printing we got reference to the object. Now consider below code.
class topics():
def __init__(self,topics):
print "inside init"
self.topics=topics
def __str__(self):
print "Inside __str__"
return "My topics is " + self.topics
my_top = topics("News")
print(my_top)
Output:
inside init
Inside __str__
My topics is News
So, here instead of object we are printing the object. As we can see we can customize the output as well. Now, whats the importance of it in a django models.py file?
When we use it in models.py file, go to admin interface, it creates object as "News", otherwise entry will be shown as main.topics instance at 0x0000000006483AC8 which won't look that much user friendly.
The __str__ function is used add a string representation of a model's object, so that is
to tell Python what to do when we convert a model instance into a string.
And if you dont mention it then it will take it by default the USERNAME_FIELD for that purpose.
So in above example it will convert Blog and Author model's object to their associated name field and the objects of Post model to their associated headline field
Django has __str__ implementations everywhere to print a default string representation of its objects. Django's default __str__ methods are usually not very helpful. They would return something like Author object (1). But that's ok because you don't actually need to declare that method everywhere but only in the classes you need a good string representation. So, if you need a good string representation of Author but not Blog, you can extend the method in Author only:
class Author(models.Model):
name = models.CharField(max_length=100)
...
def __str__(self):
return f'{self.name}' # This always returns string even if self.name is None
class Post(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
text = models.CharField(max_length=100)
author = Author.objects.create(name='David')
print(author) # David
post = Post.objects.create(author=author, text='some text')
print(post) # Post object(1)
Now, beyond Django, __str__ methods are very useful in general in Python.
More info here.
When you want to return the objects in that class then you'll see something such as <QuerySet [object(1)]>. However no body wants to see something like this. they want actual name that human can understand what exactly is present in that table, so they use this function.
For example, you define __str__() in Person model as shown below:
# "models.py"
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
def __str__(self): # Here
return self.first_name + " " + self.last_name
Then, you define Person admin as shown below:
# "admin.py"
from django.contrib import admin
from .models import Person
#admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
pass
Now, the full name is displayed in the message and list in "Change List" page:
And in "Change" page:
And in "Delete" page:
Next, if you don't define __str__() in Person model as shown below:
# "models.py"
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
# def __str__(self): # Here
# return self.first_name + " " + self.last_name
Now, the object name and id are displayed in the message and list in "Change List" page:
And in "Change" page:
And in "Delete" page:
I have made Custom User model in my Django project. Here it is:
class CustomUser(User):
avatar = models.ImageField(upload_to='avatars')
about_myself = models.TextField(max_length=300)
USERNAME_FIELD = 'username'
def __str__(self):
return self.username
def is_author(self):
return 'blog.change_post' and 'blog.add_post' in self.get_all_permissions()
And after it, I changed all Foreign Keys of user to new CustomUser model. It works OK. But I make one new migration and django cause error, when I want to migrate it:
ValueError: Lookup failed for model referenced by field blog.Comment.author: main.CustomUser
My blog.Comment model:
class Comment(models.Model):
content = models.TextField()
author = models.ForeignKey(CustomUser)
date_create = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey(Post)
What should I do?
Thanks!
Judging from the code you posted, you might be might be better served by extending the user model rather than replacing it. This pattern is usually called a profile model and works via a one-to-one relationship with User.
Profiles provides application specific fields and behaviors, while allowing User to go about it's usual business unchanged. It doesn't require you to muck around with rewriting auth or even necessarily change your foreign keys.
Here's an example of your code written as a profile:
class Profile(models.Model):
# Link to user :
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='avatars')
about_myself = models.TextField(max_length=300)
def __str__(self):
return self.user.username
def is_author(self):
return 'blog.change_post' and 'blog.add_post' in self.user.get_all_permissions()
Comment model:
class Comment(models.Model):
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL)
date_create = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey(Post)
# How to access the profile:
def check_author(self):
self.author.profile.is_author()
You'll also want to add a signal to create a new profile when a user is registered:
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
Django docs on extending users.
If a profile approach doesn't work for you, try inheriting from AbstractUser or AbstractBaseUser instead of User. The abstract models provide the same basic functionality as User and are the preferred technique for recent Django versions.
There are a handful of additional steps however, check out the docs on creating custom users for a run down.
I would like to define a django model which has many-to-one relationship with itself. It is a user profile, connected as a OneToOne field with the authentication user model. I would like to save which user (if any) was the one who referred the 'current' user to my system. This means I have the following definition:
class UserProfile(models.Model):
user = models.OneToOneField(User, blank=True, related_name='profile')
class Meta:
abstract = True
class SpecificUserProfile(UserProfile):
referrer = models.ForeignKey('self')
I saw the django defaults to naming the set of referenced models by the name of the class with a suffix _set. I believe I will be getting something along the lines of specific_user_profile_set. I would much prefer to have it named u1.referrer and u2.referred or u2.referred_set. Is there any way this can be achieved?
related_name='profile'
This is the argument to define a name for any related field, so:
class SpecificUserProfile(UserProfile):
referrer = models.ForeignKey('self', related_name='referred')
I am writing an application to help employees track projects the are working on.
Part of the form should allow logged in employees to click a drop down and see all projects they are working on. This is the part I am struggling with; specifically getting ONLY the logged in user's projects populated in a drop down. Any help or insight is much appreciated. Thanks……
models.py
class Photo(models.Model):
image = models.ImageField(upload_to='uploads/images/photo')
title = models.CharField(max_length=50)
def __unicode__(self):
return self.title
class Employee(models.Model):
user = models.ForeignKey(User, unique=True)
photo = models.ImageField(upload_to='uploads/images')
department = models.ForeignKey(Department, null=True)
phone = PhoneNumberField("Phone")
def __unicode__(self):
return self.user.get_full_name()
class Projects(models.Model):
name = models.CharField(max_length=40)
student = models.ForeignKey(Student)
photos = models.ManyToManyField(Photo, blank=True, null=True)
forms.py
class ProjectsForm(forms.ModelForm):
employee = get_object_or_404(Employee, user=user)
employee_projects = employee.projects_set.all()
name = forms.ModelChoiceField(queryset=employee_projects,
empty_label="(Select a Project)", required=True)
class Meta:
model = Projects
You need to put first two lines from ProjectsForm class definition to its initialization method and change them a bit.
class ProjectsForm(forms.ModelForm):
name = forms.ModelChoiceField(queryset=Employee.objects.all(),
empty_label="(Select a Project)", required=True)
class Meta:
model = Projects
def __init__(self, user, *args, **kwargs):
super(self, ProjectsForm).init(*args, **kwargs)
employee = get_object_or_404(Employee, user=user)
self.fields['name'].queryset = employee.projects_set.all()
Now, some explanation. Hope someone will find it useful.
In your original ProjectsForm definition, you're trying to get employee's projects when your class is defined. But this happens once your forms.py file is compiled, which takes place rarely (when you change code, for example). Also, you of course have no data that is necessary to filter projects, i.e., no user object, at that stage.
Instead, you need to do this each time the class is initialized. Initialization in Python takes place in special __init__() method. For example, when you're doing something like
form = ProjectsForm(data=request.POST)
in your view, what happens is that ProjectsForm.__init__(data=request.POST) is called to initialize ProjectsForm into an instance.
So, in our new definition, we're requiring a new argument (user) to be passed to the form when it's instantiated. So you can do something like this in your view:
form = ProjectsForm(request.user, data=request.POST)
In new initialization method, first we're calling the initialization method of parent class (which does some internal django things and should be called anyway), then use argument user to get related employee, and then assign a queryset with that employee's projects to the name field.
Sorry if I'm being too verbose.
See also:
Django, passing information when modifying queryset for ModelForm
django - dynamic select fields in forms
Why not have a many to many field in the Employee model that points to all the projects the employee can work on?
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField
I think that would be the best way to do it.