Hi Djangonauts,
I am new to Django please forgive any silly mistake in logic or code.
Intro:
I am building a web app in which members can write posts on a topic and offer courses on that topic. Example A member can write a blog about doing a wheelie on a bicycle and offer courses on that.
What I want:
I want members who want to offer courses to be verified. Example: The member has to fill a form with their details like...
name, address, and photo ID. Plus pay a charge of $9.99 to get verified. After admin (I in this case) checks if everything is good I will approve them. and then they will be "Verified Members" and be able to offer courses
What I have so far: Right now members can offer courses as there is no verified clause
class Event(models.Model):
user = models.ForeignKey(User, related_name='seller')
post = models.ForeignKey(Post, related_name='course')
price = models.DecimalField(max_digits=6, decimal_places=2)
stock = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(35)])
date = models.DateField()
time_from = models.TimeField()
time_to = models.TimeField()
event_types = (
('1', 'Webinar'),
('2', 'Actual Meet'),
)
event_choice = models.CharField(max_length=1, choices=event_types)
def get_absolute_url(self):
return reverse('posts:single', kwargs={'username': self.user.username,
'slug': self.post.slug})
def __str__(self):
return 'Meet for ' + self.post.title
How I plan to do it: I was planning to add a group in Django's admin AUTHENTICATION AND AUTHORIZATION
Home › Authentication and Authorization › Groups › Add group
Name: Verified
Permissions: Chosen permissions
event| event| Can add event
event| event| Can change event
event| event| Can delete event
Now what do I do from here?: Have I done things right so far, How do I take it from here. Do I create a model called verified and add forms.py to have members verified. How do permissions come in the picture.
My monkey patch (not a part of the question, for #Ojas Kale )
class Contact(models.Model):
user_from = models.ForeignKey(User, related_name='supporter')
user_to = models.ForeignKey(User, related_name='leader')
def __str__(self):
return '{} follows {}'.format(self.user_from, self.user_to)
User.add_to_class('following',
models.ManyToManyField('self', through=Contact, related_name='followers', symmetrical=False))
One way to go about it is adding a is_verified column in the user. There are various ways for doing this. but extending from abstractUser is probably the most straightforward and suitable in your case, since the class django.contrib.auth.models.AbstractUser provides the full implementation of the default User as an abstract model.
in your app_name.models.py create user class like this.
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
is_verified = models.BooleanField(default=False)
in your settingps.py
AUTH_USER_MODEL = 'app_name.User'
notice how app_name is used.
Now you can add as many attributes as you want as well.
By defaul is_verified is set to False, As soon as admin approves (verifies) the user change it to True.
Hope this helps.
Related
I am writing an application which allows a user to authenticate and view objects only within their organisation. For a generic.ListView, I can restrict access with the code below:
models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
organisation = models.ForeignKey('Organisation', null=True, on_delete=models.CASCADE)
class Organisation(models.Model):
name = models.CharField(max_length=255, unique=True, null=False, verbose_name="Name")
views.py
class OrganisationList(LoginRequiredMixin, generic.ListView):
model = Organisation
def get_queryset(self):
return Organisation.objects.filter(id=self.request.user.organisation.id)
In addition to this view the user will access forms, an API and the django admin interface that require this restriction.
For example, user Brett belongs to Kids Incorporated. When he logs in to the admin panel he can currently also see ACME Corporation but should not be able to do so.
I have looked at ModelManager interface but I am not sure how to get the user request and override
Is there a way to run write one query for all views (DRY) that so that a user will only see their own organisation?
There is a way.
Install django-crequest package: https://github.com/Alir3z4/django-crequest#installing
Create a model.Manager within models.py and override the get_queryset method
models.py
...
from crequest.middleware import CrequestMiddleware
class UserOrganisationManager(models.Manager):
def get_queryset(self):
request = CrequestMiddleware.get_request()
return super().get_queryset().filter(id=request.user.organisation.id)
class Organisation(models.Model):
name = models.CharField(max_length=255,
unique=True, null=False, verbose_name="Name")
...
objects = UserOrganisationManager()
You should use groups and permissions for that, a group per organization. And only members of some group can read (the permission) objects within their organization group.
This will allow you to have more that one organization for a user or vice-versa. And of course no require any other dependency.
I have a model Payment with fields: date_created, comment, description, amount. Each payment belongs to User.
class Payment(models.Model):
author = models.ForeignKey('auth.User')
amount = models.FloatField(max_length=10)
description = models.CharField(max_length=128)
created_date = models.DateTimeField(
default=datetime.now())
comment = models.TextField(max_length=256)
def __str__(self):
return self.description
Now I need to implement different roles for User: regular (can CRUD his payments), manager (can CRUD users), admin (can CRUD everything). So, the main question is how to implement this roles for users during registration (further it can't be changed). I also need to be able to set this role during registration via api (django rest framework).
Finally decided to user Django built-in Permissions
#e.g.
content_type = ContentType.objects.get_for_model(User)
permission = Permission.objects.get(codename='admin_can_manage_users')
user.user_permissions.add(permission)
I have several models that have a ForeignKey back to a model which has a ForeignKey back to auth User in Django.
models.py
class UserDetails(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='userdetail_related')
details = models.CharField(max_length=100)
email = models.EmailField(unique=True)
class UserInformation(models.Model):
user = models.ForeignKey(
UserDetails,
related_name='userinfo_related')
info = models.CharField(max_length=100, default='this')
EDIT
My actual code for related_name as per Django Documentation is: related_name='%(app_label)s_%(class)s_related'. I put 'userdetail_related' for ease of explanation here.
Only one UserDetail per User, but many UserInformation per UserDetail.
Where there is an unregistered user and we have captured their email, the email can have UserDetail and UserInformation associated with it for a shopping cart guest checkout system.
In my View I want to access the UserInformation model from self.request.user.
I can access UserDetails in my view via:
details = self.request.user.userdetail_related.filter(
user=self.request.user).first()
But I can't seem to access UserInformation via:
info = self.request.user.userdetail_related.filter(
user=self.request.user).first().userinfo_related.filter(
info='this').first()
The only way I can get this to work is:
details = self.request.user.userdetail_related.filter(
user=self.request.user).first()
info = details.userinfo_related.filter(
info='this').first()
But this surely hits the database twice which I don't want.
Does anyone have a better way of getting the info from UserInformation using the session user 'through' UserDetails?
You can use following:
user_info = UserInformation.objects.filter(user__user=self.request.user).first()
Additionally, when you access UserDetails you don't really need the filter since you are trying to access the related objects from the user itself. So following would work as well.
details = self.request.user.userdetail_related.first()
And as a side note, I think you need OneToOneField here since one user should have only one UserDetails.
As it suggested by #AKS you should use OneToOneField to connect your models to the User. You can do it like this:
class UserDetails(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
related_name='userdetail_related')
details = models.CharField(max_length=100)
class UserInformation(models.Model):
user = models.OneToOneField(
UserDetails,
related_name='userinfo_related')
info = models.CharField(max_length=100, default='this')
Then you can access UserInformation and UserDetails like this:
details = self.request.user.userdetail_related.details
info = self.request.user.userinfo_related.info
To add to the other answers, a few remarks about the layout.
For Model names, best to always use singular (UserDetails -> UserDetail), not plural. Then, for the related name of a ForeignKey, use the plural (because the reverse lookup may find more than one item that have the backwards relationship).
class UserDetail(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='details')
details = models.CharField(max_length=100)
class UserInformation(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='info')
info = models.CharField(max_length=100, default='this')
Makes it much simpler to access in the views
request.user.infos.all().first()
request.user.details.filter(info__startswith="something")
Also, if practical, add both onto the User object, because "flat is better than nested" .
If every User only has one UserDetail and one UserInformation then its best to use OneToOneFields instead.
I want to model the following application: an Owner has different Shops and each Shop has some Customers and some Employees working for that Shop; the same Employee can work in different Shops belonging to the same Owner, but also in Shops belonging to different Owners.
Only Owner and Employee can login into the system, Customer can't login.
I created the following models and added users to different Groups (using Django Auth system and version 1.6.2 which allows custom user models), but I'm concerned with the number of query that the application is doing and I'm really not sure about the modeling.
The big difficulty is that, if the Owner has various Shops, when the Owner login into the system he needs to choose which Shop is working with, also to be able to add the related Employees and Customers (only the Owner of the Shop can add Employees and Customers)
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.CharField(max_length=254,
unique=True)
firstname = models.CharField(max_length=64)
lastname = models.CharField(max_length=64)
...
objects = CustomUserManager()
USERNAME_FIELD = 'email'
...
class Shop(models.Model):
name = models.CharField(...)
city = ...
address = ...
class Customer(models.Model):
shop = models.ForeignKey(Shop)
...
class Employee(CustomUser):
shops = models.ManyToManyField(Shop)
...
class Owner(CustomUser):
shops = models.ManyToManyField(Shop)
...
Now, when the Employee or the Owner login into the system with his email, the app needs to show a select box with the available shops, and the choice of the user need to pass to every view of the application: how do I do that? I suppose can't be a POST since I'll have other forms in the app, should be a GET request, but on every request I need to verify is the Shop belongs to the Owner or to the Employee (increasing number of queries). I already developed a big part of the application (order form for example) but I'm coming back to the beginning; I don't know if all the models I've done should be related to the Shop or to the Owner.
Any advice is appreciated. Thanks.
I have solved a similar problem using sessions and custom middleware based on Django's authentication middleware:
shop/middleware.py
from django.utils.functional import SimpleLazyObject
from <appname> import shop
def get_shop(request):
if not hasattr(request, '_cached_shop'):
request._cached_shop = shop.get_shop(request)
return request._cached_shop
class ShopMiddleware(object):
def process_request(self, request):
assert hasattr(request, 'session'), "The Shop middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.shop = SimpleLazyObject(lambda: get_shop(request))
shop/__init__.py
from django.core.exceptions import ObjectDoesNotExist
from <appname>.shop.models import Shop
SHOP_SESSION_KEY = '_session_shop_id'
def get_shop(request):
try:
shop_id = request.session[SHOP_SESSION_KEY]
shop = Shop.objects.get(id=shop_id)
return shop
except (KeyError, ObjectDoesNotExist):
return None
def switch_shop(request, shop):
if not isinstance(request.user, CustomUser):
request.session[SHOP_SESSION_KEY] = None
if request.user.shops.filter(id=shop.id).exists():
request.session[SHOP_SESSION_KEY] = shop.id
Then just add ShopMiddleware to your middleware classes, and request.shop will always point to the current shop if one is selected.
In my case I have also written a view wrapper similar to login_required that redirects to a page that allows selection of a shop whenever one is required and not selected. Take a look at login_required's source code for a good pointer in the right direction.
EDIT: You still need to select a shop, so write a view that presents the user with the right options, and let it call switch_shop(request, shop). If the shop is a valid shop for the current user, the session will be set to that shop until it is changed or the user logs out.
I now my example can be unperfect but i think it will clarify how you should use Django for this.
(Also read this: https://docs.djangoproject.com/en/1.6/topics/db/managers/)
class ShopsUser(AbstractBaseUser, PermissionsMixin):
email = models.CharField(max_length=254,
unique=True)
firstname = models.CharField(max_length=64)
lastname = models.CharField(max_length=64)
...
objects = CustomUserManager()
USERNAME_FIELD = 'email'
...
priviledge_flag = models.CharField(choices=(('o', 'owner'), ('e', 'employe'), ('c', 'customer'))
class Customer(models.Model):
shop = models.ForeignKey(Shop)
class Shop(models.Model):
customers = models.ForeignKey(Customer, related_name='shops')
admins = models.ManyToMany(ShopsUser, related_name='managed_shops')
Now you can find all data by using you logged in user (use sessions) in view:
class SomeView(View):
def get(self, *args, **kwargs):
admin = self.request.user
all_singed_in_admin_shops = admin.managed_shops.all()
first_shop = all_singed_in_admin_shops[0]
first_shop_customers = first_shop.customers.all()
I'm been trying to create an app that allows users to follow each other profile since yesterday and today and I haven't been successful so far.
I'm having trouble creating a following function that allows me to retrieve users from a particular user he follows.
Example . If John follows Diana . I want to able to retrieve the user called Diana and use it with my modules.
I'm really sorry if this doesn't make sense . I'm trying my hardest to explain my situation.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
class Board(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
Most of these solutions gave me no query
This was one of the solutions I tried.
class UserLink(models.Model):
from_user = models.ForeignKey(User , related_name = "following_set")
to_user = models.ForeignKey(User , related_name = "follower_set")
date_added = models.DateTimeField(default = datetime.now)
def __unicode__(self):
return "%s is following %s" % (self.from_user.username,self.to_user.username)
def save(self,**kwargs):
if self.from_user == self.to_user:
raise ValueError("Cannot follow yourself ")
super(UserLink , self).save(**kwargs)
class Meta:
unique_together = (('to_user','from_user'),)
I tried to retrieve the users that a particular user followed and use it against my modules such as Person but it gave me an error No query exist.
def Follow(request,username=""):
if request.method == "POST":
username = request.POST.get('follow',False)
user = User.objects.get(username=username)
UserLink.objects.create(from_user=request.user,to_user=user)
return HttpResponseRedirect(reverse('world:Profile'))
return HttpResponseRedirect(reverse('world:Profile'))
I also tried this following function but it only followed himself and I changed self to User but it didn't allow me to put the person to follow
class UserProfile(models.Model):
user = models.OneToOneField(User)
follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False)
>>>from pet.models import *
>>>from django.contrib.auth.models import User
>>>user = User.objects.get(username='Peter')
>>>user1 = User.objects.get(username='Sarah')
>>>p = UserProfile.objects.filter(user=user,follows=user1)
>>>Error no field called follows
How can I create a following class that allows retrieve the people that they followed and use it with my modules such as Person?
Can someone help me . Thannk you community!
If I understand correctly, youu are on the right track with the many to many relationship. What you need is to modify your existing Person class to include this information.
Since information about who someone follows or is following is essentially information about that person and so you shouldn't really need to define a new class to implement that functionality.
I would suggest modifying your Person like so.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
following = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True, null=True)
What this line does is makes a many to many relationship between the class Person and its self.
Many to many relationships work a little different to other relationships and I suggest you read the Django documentation https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/.
But you should now be able to setup and access the relationship like this.
>>>john = Person.objects.get(name="John")
>>>diana = Person.objects.get(name="Diana")
>>>john.following.add(diana)//setup the many to many relationship
>>>john.save()
>>>john.following.all()
//This should return a queryset of Person objects which john is following.
//eg Diana
>>>diana.followers.all()
//This should return a queryset of Person objects which are following Diana.
//eg. John.
Easy, how awesome is Django!