I am trying to make multiple profile for Userena - each User can only have one Profile type. Following other discussions, I am using multiple table inhertience, but when I do this, I cannot get data to be saved into the derived models. Everything ends up being CommonProfile, which should not be possible/permitted. Example code follows:
in models.py:
# models.py
# This is an example of how i've attempted to get
# multiple user profiles working with Userena
from django.contrib.auth.models import User
from django.db import models
from userena.models import UserenaLanguageBaseProfile
class CommonProfile(UserenaLanguageBaseProfile):
"""Common fields for 2 user profiles: Spam and Eggs"""
user = models.OneToOneField(User)
common_field = models.CharField(max_length=100)
#property
def is_spam(self):
"""Find out if this is a Spam user"""
try:
self.spamprofile
return True
except SpamProfile.DoesNotExist:
return False
def get_real_type(self):
"""return the real model"""
if self.is_spam:
return self.spamprofile
else:
return self.eggsprofile
class SpamProfile(CommonProfile):
spam_field = models.CharField(max_length=20)
class EggsField(CommonProfile):
eggs_field = models.SmallIntegerField()
in forms.py
# forms.py
# This is the form to sign up a Spam Type Person
from django import forms
from userena.forms import SignupFormTos
from . models import CommonProfile, SpamProfile
class SpamSignupForm(SignupFormTos):
"""signup a Spam Person"""
common_field = forms.CharField(label='what is your quest')
spam_field = forms.CharField(label='what kind of spam are you')
def clean(self):
cleaned_data = super(SpamSignupForm,self).clean()
#do stuf, same idea for clean_<field>
return cleaned_data
def save(self):
"""Save the SpamProfile"""
user = super(SpamSignupForm,self).save()
common_profile = user.get_profile()
spam_profile = SpamProfile(commonprofile_ptr=common_profile)
spam_profile.spam_field = self.cleaned_data['spam_field']
spam_profile.save()
return spam_profile
I had the same problem this weekend. Try in your save function
def save:
#your other code
spam_field = self.cleaned_data['spam_field']
new_spam_user = SpamProfile.objects.create_user(spam_field)
return new_user
Related
I'm a beginner in Django, I created a simple ecommerce app and I'm writing some tests in tests.py.
I'm trying to write a test which check the correct creation of an OrderItem, but I don't know how to obtain an user instance.
Should I check the logged in user or the existence of the user is enough?
This is my store/models.py:
from tkinter import CASCADE
from django.db import models
from django.conf import settings
class Item(models.Model):
name = models.CharField(max_length=50)
price = models.FloatField()
def __str__(self):
return self.name
class OrderItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
def __str__(self):
return f"{self.quantity} of {self.item.name}"
#property
def get_total_price(self):
return self.quantity*self.item.price
And this store/tests.py:
def create_item(name='cintura', price=10):
return Item.objects.create(name=name, price=price)
def get_user():
return User.objects.get(username='foo')
def create_orderitem(quantity=2, user=get_user(), ordered=False):
item = create_item()
return OrderItem.objects.create(item=item, quantity=quantity, user=user, ordered=ordered)
class OrderItemModelTest(TestCase):
def test_orderitem_creation(self):
order_item = create_orderitem()
self.assertFalse(order_item.ordered)
self.assertGreater(order_item.quantity, 0, 'Quantity must be > 0')
#put here user check
This is the error:
django.db.utils.IntegrityError: The row in table 'store_orderitem' with primary key '1' has an invalid foreign key: store_orderitem.user_id contains a value '1' that does not have a corresponding value in auth_user.id.
You need something like this:
def setUp(self):
self.user = User.objects.create_user(username='testuser', password='password')
factory = RequestFactory()
request = factory.get('')
request.user = self.user
self.client.login(username='testuser', password='password')
In your tests use self.client as a ready user.
Django clears the database between tests. If you call your get_user() already in function's signature it gets executed before the test class.
If you want to keep your structure like it is now you have to move it into the function:
def create_orderitem(quantity=2, user=None, ordered=False):
if user is None:
user = get_user()
item = create_item()
return OrderItem.objects.create(item=item, quantity=quantity, user=user, ordered=ordered)
I'm a newbie to Unit testing. As I need to perform test case for following models, serializers, views & urls. Can anyone please help.
Models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth import get_user_model
# Create your models here.
class User(AbstractUser):
"""This Class is used to extend the in-build user model """
ROLE_CHOICES = (('CREATOR','CREATOR'),('MODERATOR','MODERATOR'),('USERS','USERS'))
GENDER_CHOICES = (('MALE','MALE'),('FEMALE',"FEMALE"),('OTHER','OTHER'))
date_of_birth = models.DateField(verbose_name='Date of Birth', null=True)
profile_image = models.ImageField(upload_to='media/profile_images', verbose_name='Profile Image', default='media/profile_images/default.webp', blank=True)
bio = models.TextField(verbose_name='Bio')
role = models.CharField(max_length=10, verbose_name='Role', choices=ROLE_CHOICES)
gender = models.CharField(max_length=6, verbose_name='Gender', choices=GENDER_CHOICES)
Serializers.py
class UserSerializer(serializers.ModelSerializer):
following = serializers.SerializerMethodField()
followers = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('first_name','last_name','username','password','email','date_of_birth',
'profile_image','bio','role','gender', 'following','followers')
extra_kwargs = {'is_active':{'write_only':True},
'password':{'write_only':True}}
def create(self, validated_data):
logger.info('Information Incoming!')
return User.objects.create_user(**validated_data)
def update(self, *args, **kwargs):
user = super().update( *args, **kwargs)
p = user.password
user.set_password(p)
user.save()
return user
def get_following(self, obj):
return FollowingSerializer(obj.following.all(), many=True).data
def get_followers(self, obj):
return FollowersSerializer(obj.followers.all(), many=True).data
Views.py
class UserAPI(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
# permission_classes = [permissions.IsAuthenticated, TokenHasReadWriteScope]
I tried implementing unit test case but getting an error self.assertEquals(user.get_last_name(), "Johnson") - AttributeError: 'User' object has no attribute 'get_last_name'
tests.py
class UserTests(TestCase):
def setUp(self):
User.objects.create(
first_name='Louis',last_name='Johnson',username='louis.johnson',
email='louis#mail.com',date_of_birth='1994-12-12', bio='Hello I am Louis',
role='MODERATOR',gender='MALE')
def test_users_model(self):
user = User.objects.get(first_name='Louis')
self.assertEquals(user.get_last_name(), "Johnson")
self.assertEquals(user.get_username(), "louis.johnson")
Can anyone please help in sorting out these. Any detailed documentation or help from your end would be a great support.
The user object does not have a function like get_last_name. You can call the attribute directly like that:
def test_users_model(self):
user = User.objects.get(first_name='Louis')
self.assertEquals(user.last_name, "Johnson")
...
I am trying to select all class for a user and then load all of the classes objects that are corresponding. Here is my model.py file:
from django.db import models
from django.contrib.auth.models import User
class Class(models.Model):
name = models.CharField(max_length=150)
description = models.TextField()
teacher = models.ForeignKey(User)
class UserClasses(models.Model):
class_name = models.ForeignKey(Class)
user = models.ForeignKey(User)
And here is the call i'm making:
def index(request):
#grab all classes for a user
users_classes = UserClasses.objects.filter(user=request.user)
#pass the array of class objects and get their info
classes = Class.objects.select_related(self=users_classes)
context_dict = {}
return render(request, 'dashboard/index.html', context_dict)
How can I achieve the above?
You can do
users_classes = UserClasses.objects.filter(user=request.user)
classes = Class.objects.filter(class_name__in=users_classes)
Now classes objects contains all class which user belongs to.
I still cant seem to put a simple program together. I am thinking of a simple program where my coworkers and I could propose a bet with each other. (example: I bet the detriot Lions dont win another game this season) If someone is feeling up to the task of taking that bet they can just hit an accept button. I want the user to be logged in and upon submitting the bet_name and bet_desc of the bet, their username, bet_name, bet_desc, and timestamp is saved to a table. Then a relationship table would save the bet id, win, tie, created_user_id, accepted_user_id, accepted_timestamp, and cancelled. Then userprofile table to keep their username, wins, losses, ties, bets_made, and bets_accepted.
models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
class UserProfiles(models.Model):
username = models.OneToOneField(User)
wins = models.PositiveIntegerField(default=0)
losses = models.PositiveIntegerField(default=0)
ties = models.PositiveIntegerField(default=0)
bets_made = models.PositiveIntegerField(default=0)
bets_accepted = models.PositiveIntegerField(default=0)
def __str__(self):
return "%s's profile" % self.username
class Bets2(models.Model):
bet_name = models.CharField(max_length=30)
bet_desc = models.CharField(max_length=300)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
created_user = models.OneToOneField(UserProfiles, primary_key=True)
accepted_user = models.PositiveIntegerField(default=0)
accepted_timestamp = models.DateTimeField(auto_now=True)
win = models.BooleanField(default=True)
tie = models.BooleanField(default=True)
cancelled = models.BooleanField(default=True)
def __str__(self):
return "%s's profile" % self.bet_name
As far as forms.py and views this is all i have so far:
forms.py
from django import forms
from django.core.exceptions import ValidationError
from .models import Bets2, UserProfiles
class BetForm(forms.ModelForm):
class Meta:
model = Bets2
fields = ['bet_name', 'bet_desc',]
def clean_name(self):
bet_name = self.cleaned_data.get('bet_name')
#write code here
return name
def clean_bet(self):
bet_desc = self.cleaned_data.get('bet_desc')
#write code here
return bet
views.py
from django.shortcuts import render
from django.conf import settings
from .forms import BetForm
from .models import Bets2, UserProfiles
def home(request):
title = "2015 Boardbets"
queryset = Bets2.objects.all().order_by('timestamp')
queryuser = UserProfiles.objects.all()
context = {
"title": title,
"queryset" : queryset,
"queryuser" : queryuser,
}
return render(request, "home.html", context)
def boardbet(request):
form = BetForm(request.POST or None)
bet_variables = Bets2.objects.all()
context = {
"form" : form,
"bet_variables" : bet_variables,
}
if form.is_valid():
form.save()
return render(request, "bets.html", context)
This is where i get stumped, i dont know how to incorporate the other two models into the view so that all three tables get created and also how to reference them in the template.
Edit: changed it to one model for Bets
For academic purposes, I am creating software that can manage a company's clients, project, and staff members. I figured out that by referencing a foreignkey in a separate model, you can get two models to display next to each other and be related. The problem is, is that it only displays one item for each model.
For example: You have a project your company is working on. In the admin section, it displays the project name and a single staff member. However, it should be displaying 2+ staff members.
Here's the file layout (I tried creating a separate app for different fields clients being the primary and projects the secondary):
clients.admin:
from django.contrib import admin
from django.db import models
from clients.models import Status, Project, Staff_Member, Client
class StatusInline(admin.TabularInline):
model = Status
extra = 0
class Staff_MemberInline(admin.TabularInline):
model = Staff_Member
extra = 5
project = models.ForeignKey(Project)
class ProjectInline(admin.TabularInline):
model = Project
extra = 1
class ClientAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['name']}),
]
inlines = [ProjectInline, StatusInline]
search_fields = ['name']
admin.site.register(Client, ClientAdmin)
#admin.site.register(Project)
admin.site.register(Staff_Member)
next file
clients.models:
from django.db import models
import datetime
from django.utils import timezone
# Create your models here.
class Client(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
#def was_published_recently(self):
# return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
#was_published_recently.admin_order_filed = 'pub_date'
#was_published_recently.boolean = True
#was_published_recently.short_description = 'Published recently?'
class Status(models.Model):
client = models.ForeignKey(Client)
#staff_member = models.ForeignKey(Staff_Member)
#project = models.ForeignKey(Project)
status_text = models.CharField(max_length=200)
def stat(self):
return self.status_text
def __unicode__(self):
return self.status_text
class Staff_Member(models.Model):
#status = models.ForeignKey(Status)
#project = models.ForeignKey(Project)
#client = models.ForeignKey(Client)
staff_member_text = models.CharField(max_length=200)
def __unicode__(self):
return self.staff_member_text
def mem(self):
return self.staff_member_text
class Project(models.Model):
client = models.ForeignKey(Client)
project_text = models.CharField(max_length=200)
staff_member = models.ForeignKey(Staff_Member)
#status = models.ForeignKey(Status)
def __unicode__(self):
full_name = self.client.name +'\'s '+ self.project_text
return full_name
def project_name(self):
return self.project_text
name = client.name
next file
projects.admin:
from django.contrib import admin
from django.db import models
from clients.models import Project, Status, Client
from clients.admin import StatusInline, Staff_MemberInline
class ClientInline(admin.TabularInline):
model = Client
extra = 1
#class ProjectAdmin(admin.ModelAdmin):
# inlines = [Staff_MemberInline, ClientInline]
#admin.site.unregister(Project)
admin.site.register(Project)#, ProjectAdmin)
next file
projects.models
from django.db import models
import datetime
from django.utils import timezone
from django.db import models
from clients.models import *
# Create your models here.
I'm pretty new to stackoverflow, so if there's a way I'm missing to make this more eye-friendly let me know.
Thanks!
Change extra = 1 to a higher number. More info in the docs.