Flask-admin not recognising current_user in model View - flask

I created my ModelView in flask-admin and want to give role choices to user such that only admin can create user with role manager,admin or user. And user shouldn't have choice to give admin privilidges or as such. I am trying this code but it's giving me:
AttributeError: 'NoneType' object has no attribute 'is_authenticated'
class UserView(ModelView):
column_exclude_list = ['logs', 'password_hash',]
form_excluded_columns = ['logs']
can_edit = True
if login.current_user or current_user.is_authenticated:
if login.current_user.role == 'a':
form_choices = {
'role': [ ('a', 'Admin'), ('m', 'Manager'), ('u', 'User') ]
}
if login.current_user.role == 'm':
form_choices = {
'role': [
('m', 'Manager'),
('u', 'User')
]
}
Any help would be highly appreciated.

Evaluating current_user always returns a NoneType unless it is within a Flask application context. Do something like the following:
def get_user_roles():
_roles = []
if current_user and current_user.is_authenticated:
if current_user.role == 'a':
_roles = [('a', 'Admin'), ('m', 'Manager'), ('u', 'User')]
elif login.current_user.role == 'm':
_roles = [('m', 'Manager'), ('u', 'User')]
return _roles
class UserView(ModelView):
form_choices = {
'role' : get_user_roles
}
Single file example. If you run this without logging in you will see only the "User" role in the role choices:
requirements.txt
Babel==2.11.0
blinker==1.5
click==8.1.3
colorama==0.4.6
dnspython==2.2.1
email-validator==1.3.0
Flask==2.2.2
Flask-Admin==1.6.0
Flask-BabelEx==0.9.4
Flask-Login==0.6.2
Flask-Mail==0.9.1
Flask-Principal==0.4.0
Flask-SQLAlchemy==3.0.2
Flask-WTF==1.0.1
greenlet==2.0.1
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
passlib==1.7.4
pytz==2022.6
speaklater==1.3
SQLAlchemy==1.4.44
Werkzeug==2.2.2
WTForms==3.0.1
app.py
import os
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
import click
from flask import Flask, current_app
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from flask_login import current_user, UserMixin, LoginManager
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
login_manager = LoginManager()
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Unicode(length=255), nullable=False)
last_name = db.Column(db.Unicode(length=255), nullable=False, index=True)
# Identification Data: email & password
email = db.Column(db.Unicode(length=254), nullable=False, unique=True)
password = db.Column(db.Unicode(length=255), nullable=False)
active = db.Column(db.Boolean(), default=False)
role = db.Column(db.Unicode(length=255), nullable=False)
#login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'database.db')
db.init_app(app)
login_manager.init_app(app)
#app.cli.command('create-database', short_help='Create sample database')
def create_database():
"""
Create database
"""
db.drop_all()
db.create_all()
users = [
{
'email': 'paul#example.net',
'first_name': 'Paul',
'last_name': 'Cunningham',
'password': generate_password_hash('pa$$word'),
'active': True,
'role': 'a',
},
{
'email': 'jane#example.net',
'first_name': 'Jane',
'last_name': 'Smith',
'password': generate_password_hash('pa$$word'),
'active': True,
'role': 'm'
},
]
for user in users:
_user_db = User(**user)
db.session.add(_user_db)
db.session.commit()
#app.route('/')
def index(): # put application's code here
return 'Click me to get to Admin!'
admin = Admin(app, template_mode="bootstrap3")
def get_user_roles():
# default role is a user
_roles = [('u', 'User')]
if current_user and current_user.is_authenticated:
if current_user.has_role('a'):
print('Current user is an admin')
_roles = [('a', 'Admin'), ('m', 'Manager'), ('u', 'User')]
elif current_user.has_role('m'):
print('Current user is a manager')
_roles = [('m', 'Manager'), ('u', 'User')]
print(f"Roles assigned to role choices: {_roles}")
return _roles
class UserView(ModelView):
column_list = ('first_name', 'last_name', 'email', 'role')
form_columns = column_list
form_choices = {
'role': get_user_roles
}
admin.add_view(UserView(User, db.session))
if __name__ == '__main__':
app.run()
Run the following command to initialize an SQLite DB.
flask create-database

Related

Pytest-django - testing creation and passing a required User object

Apologies if this has already been answered elsewhere. I cannot find an answer which I can retrofit into my situation.
I'm new to django so I feel the problem is me not getting a fundamental grasp of a presumably basic concept here...
Using DRF and pytest-django, i'm trying to be diligent and write tests along the way before it becomes too time consuming to manually test. I can see it snowballing pretty quickly.
The issue I face is when I try to test the creation of a Catalogue, I can't get it to pass an User instance to the mandatory field 'created_by'. The logic works fine when I test manually, but writing the test itself is causing me headaches.
Many thanks in advance!
The error is:
TypeError: Cannot encode None for key 'created_by' as POST data. Did you mean to pass an empty string or omit the value?
Code provided.
# core/models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
email = models.EmailField(unique=True)
# workshop/models.py
from django.conf import settings
from django.db import models
class Catalogue(models.Model):
STATE_DRAFT = 'DRAFT'
STATE_PUBLISHED_PRIVATE = 'PUBPRIV'
STATE_PUBLISHED_PUBLIC = 'PUBPUB'
STATE_CHOICES = [
(STATE_DRAFT, 'Draft'),
(STATE_PUBLISHED_PRIVATE, 'Published (Private)'),
(STATE_PUBLISHED_PUBLIC, 'Published (Public)')
]
company = models.ForeignKey(Company, on_delete=models.PROTECT)
title = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
state = models.CharField(
max_length=10, choices=STATE_CHOICES, default=STATE_DRAFT)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
created_on = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return self.title
class CatalogueItem(models.Model):
TYPE_GOODS = 'GOODS'
TYPE_SERVICES = 'SERVICES'
TYPE_GOODS_AND_SERVICES = 'GOODS_AND_SERVICES'
TYPE_CHOICES = [
(TYPE_GOODS, 'Goods'),
(TYPE_SERVICES, 'Services'),
(TYPE_GOODS_AND_SERVICES, 'Goods & Services')
]
catalogue = models.ForeignKey(
Catalogue, on_delete=models.CASCADE, related_name='catalogueitems')
type = models.CharField(
max_length=50, choices=TYPE_CHOICES, default=TYPE_GOODS)
name = models.CharField(max_length=255)
description = models.TextField()
unit_price = models.DecimalField(max_digits=9, decimal_places=2)
can_be_discounted = models.BooleanField(default=True)
def __str__(self) -> str:
return self.name
#property
def item_type(self):
return self.get_type_display()
# workshop/serializers.py
class CatalogueSerializer(serializers.ModelSerializer):
catalogueitems = SimpleCatalogueItemSerializer(
many=True, read_only=True)
created_on = serializers.DateTimeField(read_only=True)
created_by = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
# depth = 1
model = Catalogue
fields = ['id', 'title', 'description',
'state', 'catalogueitems', 'created_by', 'created_on']
def create(self, validated_data):
company_id = self.context['company_id']
user = self.context['user']
return Catalogue.objects.create(company_id=company_id, created_by=user, **validated_data)
# workshop/views.py
class CatalogueViewSet(ModelViewSet):
serializer_class = CatalogueSerializer
def get_permissions(self):
if self.request.method in ['PATCH', 'PUT', 'DELETE', 'POST']:
return [IsAdminUser()]
return [IsAuthenticated()]
def get_queryset(self):
user = self.request.user
if user.is_staff:
return Catalogue.objects.prefetch_related('catalogueitems__catalogue').filter(company_id=self.kwargs['company_pk'])
elif user.is_authenticated:
return Catalogue.objects.filter(company_id=self.kwargs['company_pk'], state='PUBPUB')
def get_serializer_context(self):
company_id = self.kwargs['company_pk']
return {'company_id': company_id, 'user': self.request.user}
# workshop/tests/conftest.py
from core.models import User
from rest_framework.test import APIClient
import pytest
#pytest.fixture
def api_client():
return APIClient()
#pytest.fixture
def authenticate(api_client):
def do_authenticate(is_staff=False):
return api_client.force_authenticate(user=User(is_staff=is_staff))
return do_authenticate
# workshop/tests/test_catalogues.py
from core.models import User
from workshop.models import Catalogue
from rest_framework import status
import pytest
#pytest.fixture
def create_catalogue(api_client):
def do_create_catalogue(catalogue):
return api_client.post('/companies/1/catalogues/', catalogue)
return do_create_catalogue
class TestCreateCatalogue:
def test_if_admin_can_create_catalogue_returns_201(self, authenticate, create_catalogue):
user = authenticate(is_staff=True)
response = create_catalogue(
{'title': 'a', 'description': 'a', 'state': 'DRAFT','created_by':user})
assert response.status_code == status.HTTP_201_CREATED
I think you may have a problem with the user that you are using to do the test,
when you call authenticate it returns a client which is not the same as a user.
then you run the authenticate and log in as a generic user. Try making another fixture that creates a user first, authenticate with that user to return the client and then post that user you created to create_catalogue
from django.conf import settings
#pytest.fixture
def create_user() -> User:
return settings.AUTH_USER_MODEL.objects.create(
username="Test User", password="Test Password", email="testuser#example.com"
)
#pytest.fixture
def authenticate(api_client):
def do_authenticate(create_user):
return api_client.force_authenticate(create_user)
return do_authenticate
class TestCreateCatalogue:
def test_if_admin_can_create_catalogue_returns_201(self, authenticate, create_user create_catalogue):
user = authenticate(create_user)
response = create_catalogue(
{'title': 'a', 'description': 'a', 'state': 'DRAFT','created_by':create_user})
assert response.status_code == status.HTTP_201_CREATED

flask sqlalchemy error binding parameter 1 probably unsupported type

got this error while executing my aap.py...cna anyone help?`
sqlalchemy.exc.InterfaceError: (sqlite3.InterfaceError) Error binding parameter 1 - probably unsupported type.
[SQL: INSERT INTO room (r_name, created_at, created_by, r_description) VALUES (?, CURRENT_TIMESTAMP, ?, ?)]
[parameters: ('hello', <Users 13>, None)]
(Background on this error at: http://sqlalche.me/e/14/rvf5)
my module.py
from flask import Flask
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import DateTime
from sqlalchemy.sql import func
import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///C:/sqlite3/database/chat.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
class Users(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
phone_no = db.Column(db.Integer, unique=True, nullable=False)
city = db.Column(db.String(80), nullable=False)
rooms = db.relationship('Room', backref='users')
class Room(db.Model):
id = db.Column(db.Integer, primary_key=True)
r_name = db.Column(db.String(200), unique=False, nullable=False)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
created_by = db.Column(db.String(200), db.ForeignKey('users.id'), nullable=False)
r_description = db.Column(db.String(200), nullable=True)
if __name__ == '__main__':
manager.run()
db.create_all()
'''
my app.py
'''
from flask import Flask, request, jsonify
from models import db, Users, Room, app
from datetime import datetime
#app.route('/user', methods=['POST'])
def add_users():
if request.method == 'POST':
name = request.json['name']
email = request.json['email']
phone_no = request.json['phone_no']
city = request.json['city']
new_user = Users(name=name, email=email, phone_no=phone_no, city=city)
db.session.add(new_user)
db.session.commit()
room = Room(r_name='hello')
room.created_by = new_user
# room.created_at = datetime(2015, 6, 5, 8, 10, 10, 10)
db.session.add(room)
db.session.commit()
return jsonify({'message': 'successfully created user'})
if __name__ == '__main__':
app.run(debug=True)
'''
room.created_by is an integer column, so you can't assign a User instance like new_user to it.
You could assign new_user.id
room.created_by = new_user.id
but it might be more elegant to make use of the rooms relationship defined on User.
This ought to work
#app.route('/user', methods=['POST'])
def add_users():
if request.method == 'POST':
name = request.json['name']
email = request.json['email']
phone_no = request.json['phone_no']
city = request.json['city']
new_user = Users(name=name, email=email, phone_no=phone_no, city=city)
room = Room(r_name='hello')
new_user.rooms.append(room)
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'successfully created user'})

Flask Admin - how to set form_edit_rules or form_create_rules based on role of user?

I am making simple ticketing system for medium-sized organization using Flask and sqlite together with SQLAlchemy. For backend managing of data I use Flask-Admin.
The User and Ticket table looks like this:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
role = db.Column(db.Integer, default=0)
vmc_kom = db.Column(db.String(20))
name = db.Column(db.String(30), nullable=False)
phone = db.Column(db.String, default="not")
email = db.Column(db.String(40), nullable=False)
password = db.Column(db.String(60), nullable=False)
tickets = db.relationship('Ticket', cascade="all,delete", backref='author', lazy=True)
def __repr__(self):
return f"('{self.name}')"
class Ticket(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
povod_vmc_kom = db.Column(db.String(20))
osoba = db.Column(db.String(20), default="XYZ")
dateVMC = db.Column(db.Date, nullable=False)
deadline = db.Column(db.Date, nullable=False)
is_finished = db.Column(db.Boolean, default = False)
images = db.relationship('Image_ticket', cascade="all,delete", backref='home_ticket', lazy=True)
solution = db.Column(db.Text)
date_solution = db.Column(db.DateTime)
zodpovedni = db.relationship("Zodpovedny", secondary="ticketutvary")
sprava = db.Column(db.String(100))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Ticket('{self.id}', '{self.title}', '{self.dateVMC}')"
I was able to set permission to create, edit or delete Tickets based on User.role set in is_accesible method.
class TicketModelView(ModelView):
column_list = ['id', 'title', 'osoba', 'content', 'povod_vmc_kom', 'dateVMC','zodpovedni', 'deadline', 'solution']
def is_accessible(self):
if current_user.is_authenticated and current_user.role == 0:
self.can_export=True
self.can_delete = False
self.can_edit = False
self.can_create = False
return True
if current_user.is_authenticated and current_user.role == 1:
self.can_export=True
self.can_delete=True
return True
if current_user.is_authenticated and current_user.role == 2:
self.can_delete = False
self.can_export=True
return True
if current_user.is_authenticated and current_user.role == 3:
self.can_delete = False
self.can_export=True
return True
return False
But I´ve been struggling really hard to set form_edit_rules for specific user. For example I want to allow User with role == 2 to edit only two columns in Ticket. When I put form_edit_rules directly in ModelView Class it works but for everybody. I also tried this:
class TicketModelView(ModelView):
column_list = ['id', 'title', 'osoba', 'content', 'povod_vmc_kom', 'dateVMC','zodpovedni', 'deadline', 'solution']
def is_accessible(self):
if current_user.is_authenticated and current_user.role == 2:
self.can_export=True
self.can_delete = False
self.can_edit = False
self.can_create = False
self.form_edit_rules = ('zodpovedni','dateVMC')
return True
But no success.
Please can anyone push me right direction? Is there something I am missing? Is there some really bad practise used?
Thanks in advance.
form_edit_rules is already cached by the time method is_accessible is called. If you update the rules then refresh the cache:
class TicketModelView(ModelView):
column_list = ['id', 'title', 'osoba', 'content', 'povod_vmc_kom', 'dateVMC','zodpovedni', 'deadline', 'solution']
def is_accessible(self):
if current_user.is_authenticated and current_user.role == 2:
self.can_export=True
self.can_delete = False
self.can_edit = False
self.can_create = False
self.form_edit_rules = ('zodpovedni','dateVMC')
# Refresh form rules cache
self._refresh_form_rules_cache()
return True
return False
It is also possible to set the form_edit_rules at runtime without resorting to invalidating the rules cache. I used this SO Q/A flask-admin: how to allow only super users can view the specified table column? as the basis for the following. If the user is logged in and is has role 'admin' they can see and use the 'active' field.
class AuthorView(sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
#property
def _form_edit_rules(self):
return rules.RuleSet(self, self.form_edit_rules)
#_form_edit_rules.setter
def _form_edit_rules(self, value):
pass
#property
def form_edit_rules(self):
if not has_app_context() or current_user.has_role('admin'):
return ('first_name', 'last_name', rules.Text(f'Authenticated User has Admin role'), 'active')
return ('first_name', 'last_name', rules.Text('Not Authenticated and/or not Admin role'))
Full single file Python 3 example below.
requirements.txt
Babel==2.8.0
blinker==1.4
click==7.1.2
dnspython==2.0.0
email-validator==1.1.1
Faker==4.1.1
Flask==1.1.2
Flask-Admin==1.5.6
Flask-BabelEx==0.9.4
Flask-Login==0.5.0
Flask-Mail==0.9.1
Flask-Principal==0.4.0
Flask-Security==3.0.0
Flask-SQLAlchemy==2.4.4
Flask-WTF==0.14.3
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
passlib==1.7.2
python-dateutil==2.8.1
pytz==2020.1
six==1.15.0
speaklater==1.3
SQLAlchemy==1.3.18
text-unidecode==1.3
Werkzeug==1.0.1
WTForms==2.3.3
app.py
from datetime import datetime
from faker import Faker
import click
from flask import Flask, has_app_context, current_app
from flask_admin.form import rules
from flask_login import login_user, logout_user
from flask_security import UserMixin, RoleMixin, current_user, SQLAlchemyUserDatastore, Security
from flask_security.utils import hash_password
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib import sqla
db = SQLAlchemy()
user_to_role = db.Table('user_to_role',
db.Column('user_id', db.Integer(), db.ForeignKey('users.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('roles.id')))
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Unicode(length=255), nullable=False)
last_name = db.Column(db.Unicode(length=255), nullable=False, index=True)
# Identification Data: email & password
email = db.Column(db.Unicode(length=254), nullable=False, unique=True)
password = db.Column(db.Unicode(length=255), nullable=False)
active = db.Column(db.Boolean(), default=False)
roles = db.relationship('Role', secondary=user_to_role, backref=db.backref('users', lazy='select'))
class Role(db.Model, RoleMixin):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(length=64), unique=True)
description = db.Column(db.Unicode(length=255), nullable=True)
def __str__(self):
return self.name
class Author(db.Model):
__tablename__ = 'authors'
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.Text(length=255), nullable=False)
last_name = db.Column(db.Text(length=255), nullable=False)
active = db.Column(db.Boolean(), default=False)
def __str__(self):
return f"ID: {self.id}; First Name: {self.first_name}; Last Name: {self.last_name}"
app = Flask(__name__)
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sample.sqlite'
app.config['SECURITY_PASSWORD_HASH'] = 'pbkdf2_sha512'
app.config['SECURITY_PASSWORD_SALT'] = 'c1b4797ffb4783bb4aed7e14a1494a01390eacf94ee324b9'
db.init_app(app)
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
#app.cli.command('create-database', short_help='Create sample database')
#click.option('--count', default=100, help='Number of authors (default 100)')
def create_database(count):
"""
Create database
"""
db.drop_all()
db.create_all()
_faker = Faker()
security = current_app.extensions.get('security')
_admin_role = security.datastore.find_or_create_role(name="admin", description='Administers the system')
_user_role = security.datastore.find_or_create_role(name="user", description='Uses the system')
users = [
{'email': 'paul#example.net', 'first_name': 'Paul', 'last_name': 'Cunningham', 'password': hash_password('pa$$word'), 'role': _user_role},
{'email': 'jane#example.net', 'first_name': 'Jane', 'last_name': 'Smith', 'password': hash_password('pa$$word'), 'role': _admin_role},
]
for user in users:
_role = user.pop('role')
_user_db = security.datastore.create_user(**user)
if _role:
security.datastore.add_role_to_user(_user_db, _role)
security.datastore.activate_user(_user_db)
_user_db.confirmed_at = datetime.utcnow()
security.datastore.commit()
for _ in range(0, count):
_author = Author(
first_name=_faker.first_name(),
last_name=_faker.last_name(),
active=_faker.boolean()
)
db.session.add(_author)
db.session.commit()
class AuthorView(sqla.ModelView):
column_default_sort = ('last_name', False)
column_searchable_list = ('first_name', 'last_name')
#property
def _form_edit_rules(self):
return rules.RuleSet(self, self.form_edit_rules)
#_form_edit_rules.setter
def _form_edit_rules(self, value):
pass
#property
def form_edit_rules(self):
if not has_app_context() or current_user.has_role('admin'):
return ('first_name', 'last_name', rules.Text(f'Authenticated User has Admin role'), 'active')
return ('first_name', 'last_name', rules.Text('Not Authenticated and/or not Admin role'))
# Flask views
#app.route('/')
def index():
_html = [
'Click me to get to impersonate Paul (user)!',
'Click me to get to impersonate Jane (admin)!'
]
return '<br>'.join(_html)
#app.route('/impersonate-paul')
def impersonate_paul():
_impersonate_user = User.query.filter(User.email == 'paul#example.net').first()
logout_user()
login_user(_impersonate_user)
return 'Click me to get to Admin logged in as Paul (user)!'
#app.route('/impersonate-jane')
def impersonate_jane():
_impersonate_user = User.query.filter(User.email == 'jane#example.net').first()
logout_user()
login_user(_impersonate_user)
return 'Click me to get to Admin logged in as Jane (admin)!'
admin = Admin(app, template_mode="bootstrap3")
admin.add_view(AuthorView(Author, db.session))
if __name__ == '__main__':
app.run()
Run the following command to initialize an SQLite DB.
flask create-database --count 100

'StateApps' object has no attribute 'label' while running migration

As I am trying to run the this migration:
def add_user_data(apps, schema_editor):
Group = apps.get_model('auth', 'Group')
Permission = apps.get_model(
'auth', 'Permission')
Profile = apps.get_model('user', 'Profile')
User = apps.get_model('user', 'User')
andrew_user = User.objects.create(
email='django#jambonsw.com',
password=make_password('hunter2'),
is_active=True,
is_staff=True,
is_superuser=True)
andrew_profile = Profile.objects.create(
user=andrew_user,
name='Andrew',
slug='andrew',
about='The author of this site!')
ada_user = User.objects.create(
email='ada#djangogirls.org',
password=make_password('algorhythm'),
is_active=True,
is_staff=True,
is_superuser=False)
ada_profile = Profile.objects.create(
user=ada_user,
name='Ada Lovelace',
slug='the_countess',
about=(
' '))
contributors = Group.objects.create(
name='contributors')
ada_user.groups.add(contributors)
permissions = [
'add_post',
'change_post',
]
for perm in permissions:
contributors.permissions.add(
Permission.objects.get(
codename=perm,
content_type__app_label='blog'))
def remove_user_data(apps, schema_editor):
Group = apps.get_model('auth', 'Group')
Profile = apps.get_model('user', 'Profile')
User = apps.get_model('user', 'User')
Profile.objects.get(slug='andrew').delete()
Profile.objects.get(
slug='the_countess').delete()
User.objects.get(
email='django#jambonsw.com').delete()
User.objects.get(
email='ada#djangogirls.org').delete()
Group.objects.get(
name='contributors').delete()
class Migration(migrations.Migration):
dependencies = [
('blog', '0005_post_permissions'),
('user', '0002_profile'),
]
operations = [
migrations.RunPython(
add_user_data,
remove_user_data)
]
I ran in this error:
AttributeError: 'StateApps' object has no attribute 'label'
I don't really know what the 'StateApps' does. But As the error message states it has something to do with assigning the permissions. Can someone help? This code is from a tutorial using Django 1.8 so I think that it is django 1.11 which is making the code error.
Change generate_permissions function in blog/migrations/0005_post_permissions.py:
def generate_permissions(apps, schema_editor):
Permission = apps.get_model('auth', 'Permission')
try:
Permission.objects.get(
codename='add_post',
content_type__app_label='blog')
except Permission.DoesNotExist:
app_config = apps.get_app_config('blog')
if app_config.models_module is None:
app_config.models_module = True
create_permissions(app_config, verbosity=0)
app_config.models_module = None
else:
raise
It's work for me with django 2.1

upload an images using django and tastypie (python version : 2.7)

I am having a hard time figuring out a way of doing multipart/formencoded image upload using django and tastypie. I went through all the possible answers on stackoverflow but cant seem to find a solution that would work. Also, i am a beginner in python so cant seem to understand a lot of stuff. I have written some code and would like someone to point me as to what am i doing wrong.
Models.py
import random
from django.db import models
from django.template.loader import get_template
from django.template import Context
import suuq.settings
from usermanagement import utils
from django.contrib.auth.models import UserManager
from django.db.models import ImageField
class adManager(models.Manager):
def create_ad(self, category, title, email, tag, location, address, description, phone, img):
if not category:
raise ValueError('add must have a category')
if not title:
raise ValueError('add must have a title')
if not email:
raise ValueError('ad must have a email')
if not tag:
raise ValueError('ad must have a tag')
if not location:
raise ValueError('ad must have a location')
if not address:
raise ValueError('ad must have a address')
if not description:
raise ValueError('ad must have a description')
if not phone:
raise ValueError('ad must have a phone number')
if not img:
raise ValueError('ad must have a image')
ad = self.create(category = category, title = title, email = UserManager.normalize_email(email).strip().lower(),
tag = tag, location = location, address = address, description = description, phone = phone, img=img)
ad.save()
return ad
class Ad(models.Model):
objects = adManager()
category = models.CharField(max_length=100)
title = models.CharField(max_length=200)
email = models.EmailField(
max_length=255,
unique=True,
)
tag = models.CharField(max_length=200)
location = models.CharField(max_length=50)
address = models.CharField(max_length=200)
description = models.CharField(max_length=140)
phone = models.CharField(max_length=10, null=True)
img = models.ImageField(upload_to="img", null=True, blank=True)
api.py
import json
from django.conf.urls import url
from django import forms
from tastypie.authentication import SessionAuthentication
from tastypie.authorization import Authorization
from tastypie.exceptions import Unauthorized
from tastypie.resources import ModelResource
from tastypie.throttle import CacheThrottle
from tastypie.utils import trailing_slash
from tastypie.validation import FormValidation
from django.db.models import FileField
from tastypie import http, fields
from PIL import Image
from ad.models import Ad
class MultipartResource(object):
def deserialize(self, request, data, format=None):
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
return data
return super(MultipartResource, self).deserialize(request, data, format)
class AdResource(ModelResource, MultipartResource):
img = fields.FileField(attribute="img", null=True, blank=True)
class Meta:
queryset = Ad.objects.all()
resource_name = 'ad'
fields = ['id', 'category', 'title','email','tag','location', 'address', 'description', 'phone', 'img']
allowed_methods = ['post','get','delete']
include_resource_uri = False
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/add%s$" %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('add_ad'), name="add_ad"),
]
def add_ad(self, request, **kwargs):
self.method_check(request, allowed=['post'])
data = json.loads(request.body)
category = data.get('category', '')
title = data.get('title', '')
email = data.get('email', '')
tag = data.get('tag', '')
location = data.get('location', '')
address = data.get('address', '')
description = data.get('description', '')
phone = data.get('phone', '')
if(request.method == 'POST'):
if "multipart/form-data" not in str(request.META['CONTENT_TYPE']):
return
else:
if('img' in request.FILES):
upload = request.FILES['img']
img = Image.open(upload)
return
else:
return
else:
return
ad = Ad.objects.create_ad(category=category, title=title, email=email, tag=tag,
location=location, address=address, description=description, phone=phone, img=img)
return self.create_response(request, {
'success': True,
'ad_id': ad.id,
'message': 'ad address successfully added'
})
I know my code is not indented properly but i have it properly indented on my dev end. Please help me fix my logic, i am really stuck.
I found the problem and here is my updated solution using multipart form data
class AdResource(ModelResource):
img = fields.FileField(attribute="img", null=True, blank=True)
class Meta:
queryset = Ad.objects.all()
resource_name = 'ad'
fields = ['id', 'category', 'title','email','tag','location', 'address', 'description', 'phone', 'img']
allowed_methods = ['post','get','delete']
include_resource_uri = False
always_return_data = True
limit = 0
authentication = SessionAuthentication()
authorization = AdAuthorization()
throttle = CacheThrottle(throttle_at=200)
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/add%s$" %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('add_ad'), name="add_ad"),
]
def add_ad(self, request, **kwargs):
self.is_authenticated(request)
self.method_check(request, allowed=['post'])
format = request.META.get('CONTENT_TYPE')
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
category = data.get('category', '')
title = data.get('title', '')
email = data.get('email', '')
tag = data.get('tag', '')
location = data.get('location', '')
address = data.get('address', '')
description = data.get('description', '')
phone = data.get('phone', '')
img = data.get('img','')
ad = Ad.objects.create_ad(user=request.user, category=category, title=title, email=email, tag=tag,
location=location, address=address, description=description, phone=phone, img=img)
return self.create_response(request, {
'success': True,
'message': 'Ad address successfully added',
'id': ad.id
})
else:
return self.create_response(request, {
'success': False,
'message': 'Invalid format'
})