I have created the user Customer model. I migrated the model to syn with the database. However I am getting an error of User has no customer.
click to profile page through http://127.0.0.1:8000/profile But after adding profile code for every user I am getting the below error
Here is my code
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
full_name = models.CharField(max_length=200, null=True)
address = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.full_name
class CustomerProfileView(TemplateView):
template_name = "app/CustomerProfile.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
customer = self.request.user.customer
context['customer'] = customer
orders = Order.objects.filter(cart__customer=customer).order_by("-id")
context["orders"] = orders
return context
As the error says, you use a User object for which there is no related Customer object.
You thus have to construct a Customer record for all users that have no Customer. You can for example do this in a data migration [Django-doc] with:
python manage.py makemigrations --empty app_name
in the data migration you can then create a Customer for every user without a Customer:
from django.db import migrations
def create_customers(apps, schema_editor):
Customer = apps.get_model('app_name', 'Customer')
User = apps.get_model('auth', 'User')
customers = [
Customer(user=user, full_name=None, address=None)
for user in User.objects.filter(customer=None)
]
Customer.objects.bulk_create(customers)
class Migration(migrations.Migration):
dependencies = [
('app_name', '1234_some_migration'),
]
operations = [
migrations.RunPython(create_customers),
]
and then run the migration to construct customer for all already existing users.
Related
I am trying to create an announcement website (All) that can be visible to others (the Users, for which I added an Account). For this I wanted to modify a little the user profile to add fields like telephone, email address...
So I modified admin.py:
from django.contrib import admin
from .models import Todo, Account
from django.contrib.auth.models import User
class AccountInline(admin.StackedInline):
model = Account
can_delete = False
verbose_name_plural = 'Accounts'
class TodoAdmin(admin.ModelAdmin):
readonly_fields = ('created',)
inlines = (AccountInline, )
admin.site.unregister(User)
admin.site.register(Todo, TodoAdmin)
But got back:
<class 'todo.admin.AccountInline'>: (admin.E202) 'todo.Account' has no ForeignKey to 'todo.Todo'.
So I added a ForeignKey to Todo with account = models.ForeignKey(Account, on_delete=models.CASCADE):
from django.db import models
from django.contrib.auth.models import User
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email = models.CharField(max_length=100)
firstname = models.CharField(max_length=30)
lastname = models.CharField(max_length=50)
company = models.CharField(max_length=5)
def __str__(self):
return self.user.username
class Todo(models.Model):
title = models.CharField(max_length=100)
datetime = models.DateTimeField()
memo = models.TextField(blank=True)
created = models.DateTimeField(auto_now_add=True)
datecompleted = models.DateTimeField(null=True, blank=True)
important = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
def __str__(self):
return self.title
But I still have the error, and I don't have any Users in the admin panel anymore
You accidentally wrote unregister for Users in your admin.py file. It should be admin.site.register(User)
You misinterpretted the error: the error states that you don't have a foreign key in your Account model to Todo.
This means your inline admin code isn't correct as it's expecting the other way around.
The Viewset def list looks like this:
class ThreeDimensionalModelViewSet(viewsets.ViewSet):
serializer_class = ThreeDimensionalModelSerializer
queryset = ThreeDimensionalModel.objects.all()
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def list(self, request):
models = ThreeDimensionalModel.objects.all()
serializer = ThreeDimensionalModelSerializer(models, many=True)
print(request.user.id)
return Response(serializer.data)
The serializer looks like this:
class ThreeDimensionalModelSerializer(serializers.ModelSerializer):
class Meta:
model = ThreeDimensionalModel
fields = ['File', 'Uploaded', 'Owner', 'Previous', 'SharedWithUser']
read_only_fields = ['Owner']
The model looks like this:
class ThreeDimensionalModel(models.Model):
File = models.FileField(upload_to='models')
Owner = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True, related_name='Owner')
Uploaded = models.DateTimeField(auto_now_add=True)
Previous = models.ForeignKey("self", on_delete=models.SET_NULL, default=None, null=True)
SharedWithUser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='SharedWithUser')
When a user requests models at /api/models it should only show the models that are the same owner Id as his.
If no additional data is sent with that request then obviously you can't filter by user.
The straightforward way to do it is that for logged in users the cookie will contain user information such as userId.
When your endpoint recognizes the user who made the requested is logged in, it will use that as the filter for the query instead of all() as seen in the Django docs
https://docs.djangoproject.com/en/3.2/topics/db/queries/#retrieving-specific-objects-with-filters
To summarize - if the user is not logged in (or supplies the information as part of the request in some way) then the request is anonymous and there is no way to know who made it
I have two different app that has separate models that inherits from AbstractionBaseUser like below
# in doctor/models.py
...
class Patient(AbstractBaseUser):
email = models.EmailField(blank=True, unique=True)
phone_number = models.IntegerField(blank=False, unique=True)
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELD = ['phone_number', 'email']
...
# in Patient/models.py
...
class Patient(AbstractBaseUser):
email = models.EmailField(blank=True, unique=True)
phone_number = models.IntegerField(blank=False, unique=True)
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELD = ['phone_number', 'email']
...
Both models have different fields
# in settings.py
AUTH_USER_MODEL = [
'doctor.Doctor',
'patient.Patient'
]
I tried to do this but in making migration it tells me that it must be a single model
AssertionError: ForeignKey(['doctor.Doctor', 'patient.Patient']) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
I read docs but I couldn't find any help
How can I fix this and how can I have multiple AUTH_USER_MODEL
how can I have multiple AUTH_USER_MODEL.
You don't. There is one user model. It would also make all procedures more complicated. What if a the same email address occurs in both the Doctor and Patient model? Then how would you log in such person?
You can however make multiple extra models with a ForeignKey to the user model. We can for example use the default user model:
# settings.py
# …
AUTH_USER_MODEL = 'auth.User'
# …
You can of course also specify a basic user model yourself. But it should be one user model.
Then both the Doctor and Patient model can have a one-to-one relation to the User model:
from django.db import models
from django.conf import settings
class Doctor(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
# … extra doctor fields …
as well as a patient:
from django.db import models
from django.conf import settings
class Patient(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
# … extra patient fields …
You can then check for a user if it is a doctor by accessing the .doctor attribute:
from django.contrib.auth.decorators import login_required
#login_required
def some_view(request):
try:
doctor = request.user.doctor
except AttributeError:
# … user is not a doctor …
pass
pass
This also allows that a User is both a Doctor and a Patient for example. This may look odd at first. But later it is possible that you introduce more roles, and it is not impossible that the same user is assigned multiple roles, for example doctor and supervisor of a department.
I have two models, which are User and Record. Each has several fields.
from django.db import models
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,null=True)
def __str__(self):
return self.nickname
class Record(models.Model):
expression = models.CharField(max_length=100)
user = models.ForeignKey(User)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.expression
I register them in admin.py
from django.contrib import admin
from .models import User,Record
class RecordAdmin(admin.ModelAdmin):
list_display = ('expression','user','time')
class UserAdmin(admin.ModelAdmin):
empty_value_display = "空"
list_display = ('openid','nickname')
admin.site.register(User,UserAdmin)
admin.site.register(Record,RecordAdmin)
it works well in django admin initially. but one day, the fields of the Record model disppeared. It looks like
.
No field displays. It makes me unable to modify or add the values of the Record model. The other model User works well and all data exists in database. So why?
I think you just have to add on_delete=models.CASCADE in your ForeignKey Field. When you are using this kind of field, you have to specify the comportment when you make an update, a delete or anything else on this field.
So your script should be like this :
class Record(models.Model):
expression = models.CharField(max_length=100)
user = models.ForeignKey(User, on_delete=models.CASCADE)
time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.expression
This is the result :
Edit :
You can also modify null=True by default=null
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,default=null)
def __str__(self):
return self.nickname
All my models on the database should be filtered by user, always. I created for all my models a field owner which I get the user from the request and fill it in when I'm creating the models.
When I go to all urls they are filtered correctly, as well as when I create them onto the database.
But the problem is when I use the html interface to insert a model on the database, all the related items (it doesn't matter the user) are listed on the foreign key field.
My view
class TransactionList(generics.ListCreateAPIView):
serializer_class = TransactionSerializer
permission_classes = (permissions.IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get_queryset(self):
return Transaction.objects.filter(owner=self.request.user)
My serializer
class TransactionSerializer(serializers.ModelSerializer):
class Meta:
model = Transaction
fields = ('id', 'date', 'description',
'value', 'account', 'envelope', 'bill',)
My model
class Transaction(models.Model):
date = models.DateField(auto_now=True)
description = models.CharField(max_length=100)
value = models.DecimalField(max_digits=10, decimal_places=2)
account = models.ForeignKey(Account, on_delete=models.DO_NOTHING)
envelope = models.ForeignKey(Envelope, on_delete=models.DO_NOTHING, null=True)
bill = models.ForeignKey(Bill, on_delete=models.DO_NOTHING, null=True)
owner = models.ForeignKey('auth.User', related_name='transactions')
For example, with those items when I open the page for inserting the data, all the other accounts (which are restricted for user, too) appear on the combo.
How do I filter related fields for the HTML forms?
And how do I validate if related objects are not from other user?